|
Blender
V2.59
|
00001 /* 00002 * $Id: paint_vertex.c 37246 2011-06-06 11:04:54Z nazgul $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00021 * All rights reserved. 00022 * 00023 * The Original Code is: all of this file. 00024 * 00025 * Contributor(s): none yet. 00026 * 00027 * ***** END GPL LICENSE BLOCK ***** 00028 */ 00029 00035 #include <math.h> 00036 #include <string.h> 00037 00038 #ifdef WIN32 00039 #include <io.h> 00040 #else 00041 #include <unistd.h> 00042 #endif 00043 00044 #include "MEM_guardedalloc.h" 00045 00046 #include "BLI_blenlib.h" 00047 #include "BLI_math.h" 00048 #include "BLI_utildefines.h" 00049 #include "BLI_ghash.h" 00050 00051 #include "IMB_imbuf.h" 00052 #include "IMB_imbuf_types.h" 00053 00054 #include "DNA_armature_types.h" 00055 #include "DNA_mesh_types.h" 00056 #include "DNA_particle_types.h" 00057 #include "DNA_scene_types.h" 00058 #include "DNA_brush_types.h" 00059 #include "DNA_object_types.h" 00060 #include "DNA_meshdata_types.h" 00061 00062 #include "RNA_access.h" 00063 #include "RNA_define.h" 00064 #include "RNA_enum_types.h" 00065 00066 #include "BKE_DerivedMesh.h" 00067 #include "BKE_action.h" 00068 #include "BKE_brush.h" 00069 #include "BKE_context.h" 00070 #include "BKE_depsgraph.h" 00071 #include "BKE_deform.h" 00072 #include "BKE_mesh.h" 00073 #include "BKE_modifier.h" 00074 #include "BKE_object.h" 00075 #include "BKE_paint.h" 00076 #include "BKE_report.h" 00077 00078 #include "WM_api.h" 00079 #include "WM_types.h" 00080 00081 00082 #include "ED_armature.h" 00083 #include "ED_mesh.h" 00084 #include "ED_screen.h" 00085 #include "ED_view3d.h" 00086 00087 #include "paint_intern.h" 00088 00089 /* brush->vertexpaint_tool */ 00090 #define VP_MIX 0 00091 #define VP_ADD 1 00092 #define VP_SUB 2 00093 #define VP_MUL 3 00094 #define VP_BLUR 4 00095 #define VP_LIGHTEN 5 00096 #define VP_DARKEN 6 00097 00098 /* polling - retrieve whether cursor should be set or operator should be done */ 00099 00100 00101 /* Returns true if vertex paint mode is active */ 00102 int vertex_paint_mode_poll(bContext *C) 00103 { 00104 Object *ob = CTX_data_active_object(C); 00105 00106 return ob && ob->mode == OB_MODE_VERTEX_PAINT && ((Mesh *)ob->data)->totface; 00107 } 00108 00109 int vertex_paint_poll(bContext *C) 00110 { 00111 if(vertex_paint_mode_poll(C) && 00112 paint_brush(&CTX_data_tool_settings(C)->vpaint->paint)) { 00113 ScrArea *sa= CTX_wm_area(C); 00114 if(sa->spacetype==SPACE_VIEW3D) { 00115 ARegion *ar= CTX_wm_region(C); 00116 if(ar->regiontype==RGN_TYPE_WINDOW) 00117 return 1; 00118 } 00119 } 00120 return 0; 00121 } 00122 00123 int weight_paint_mode_poll(bContext *C) 00124 { 00125 Object *ob = CTX_data_active_object(C); 00126 00127 return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((Mesh *)ob->data)->totface; 00128 } 00129 00130 int weight_paint_poll(bContext *C) 00131 { 00132 Object *ob= CTX_data_active_object(C); 00133 ScrArea *sa; 00134 00135 if( (ob != NULL) && 00136 (ob->mode & OB_MODE_WEIGHT_PAINT) && 00137 (paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != NULL) && 00138 (sa= CTX_wm_area(C)) && 00139 (sa->spacetype == SPACE_VIEW3D) 00140 ) { 00141 ARegion *ar= CTX_wm_region(C); 00142 if(ar->regiontype==RGN_TYPE_WINDOW) { 00143 return 1; 00144 } 00145 } 00146 return 0; 00147 } 00148 00149 static VPaint *new_vpaint(int wpaint) 00150 { 00151 VPaint *vp= MEM_callocN(sizeof(VPaint), "VPaint"); 00152 00153 vp->flag= VP_AREA+VP_SPRAY; 00154 00155 if(wpaint) 00156 vp->flag= VP_AREA; 00157 00158 return vp; 00159 } 00160 00161 static int *get_indexarray(Mesh *me) 00162 { 00163 return MEM_mallocN(sizeof(int)*(me->totface+1), "vertexpaint"); 00164 } 00165 00166 00167 /* in contradiction to cpack drawing colors, the MCOL colors (vpaint colors) are per byte! 00168 so not endian sensitive. Mcol = ABGR!!! so be cautious with cpack calls */ 00169 00170 static unsigned int rgba_to_mcol(float r, float g, float b, float a) 00171 { 00172 int ir, ig, ib, ia; 00173 unsigned int col; 00174 char *cp; 00175 00176 ir= floor(255.0f * r); 00177 if(ir<0) ir= 0; else if(ir>255) ir= 255; 00178 ig= floor(255.0f * g); 00179 if(ig<0) ig= 0; else if(ig>255) ig= 255; 00180 ib= floor(255.0f * b); 00181 if(ib<0) ib= 0; else if(ib>255) ib= 255; 00182 ia= floor(255.0f * a); 00183 if(ia<0) ia= 0; else if(ia>255) ia= 255; 00184 00185 cp= (char *)&col; 00186 cp[0]= ia; 00187 cp[1]= ib; 00188 cp[2]= ig; 00189 cp[3]= ir; 00190 00191 return col; 00192 00193 } 00194 00195 unsigned int vpaint_get_current_col(VPaint *vp) 00196 { 00197 Brush *brush = paint_brush(&vp->paint); 00198 return rgba_to_mcol(brush->rgb[0], brush->rgb[1], brush->rgb[2], 1.0f); 00199 } 00200 00201 static void do_shared_vertexcol(Mesh *me) 00202 { 00203 /* if no mcol: do not do */ 00204 /* if tface: only the involved faces, otherwise all */ 00205 MFace *mface; 00206 MTFace *tface; 00207 int a; 00208 short *scolmain, *scol; 00209 char *mcol; 00210 00211 if(me->mcol==NULL || me->totvert==0 || me->totface==0) return; 00212 00213 scolmain= MEM_callocN(4*sizeof(short)*me->totvert, "colmain"); 00214 00215 tface= me->mtface; 00216 mface= me->mface; 00217 mcol= (char *)me->mcol; 00218 for(a=me->totface; a>0; a--, mface++, mcol+=16) { 00219 if((tface && tface->mode & TF_SHAREDCOL) || (me->editflag & ME_EDIT_PAINT_MASK)==0) { 00220 scol= scolmain+4*mface->v1; 00221 scol[0]++; scol[1]+= mcol[1]; scol[2]+= mcol[2]; scol[3]+= mcol[3]; 00222 scol= scolmain+4*mface->v2; 00223 scol[0]++; scol[1]+= mcol[5]; scol[2]+= mcol[6]; scol[3]+= mcol[7]; 00224 scol= scolmain+4*mface->v3; 00225 scol[0]++; scol[1]+= mcol[9]; scol[2]+= mcol[10]; scol[3]+= mcol[11]; 00226 if(mface->v4) { 00227 scol= scolmain+4*mface->v4; 00228 scol[0]++; scol[1]+= mcol[13]; scol[2]+= mcol[14]; scol[3]+= mcol[15]; 00229 } 00230 } 00231 if(tface) tface++; 00232 } 00233 00234 a= me->totvert; 00235 scol= scolmain; 00236 while(a--) { 00237 if(scol[0]>1) { 00238 scol[1]/= scol[0]; 00239 scol[2]/= scol[0]; 00240 scol[3]/= scol[0]; 00241 } 00242 scol+= 4; 00243 } 00244 00245 tface= me->mtface; 00246 mface= me->mface; 00247 mcol= (char *)me->mcol; 00248 for(a=me->totface; a>0; a--, mface++, mcol+=16) { 00249 if((tface && tface->mode & TF_SHAREDCOL) || (me->editflag & ME_EDIT_PAINT_MASK)==0) { 00250 scol= scolmain+4*mface->v1; 00251 mcol[1]= scol[1]; mcol[2]= scol[2]; mcol[3]= scol[3]; 00252 scol= scolmain+4*mface->v2; 00253 mcol[5]= scol[1]; mcol[6]= scol[2]; mcol[7]= scol[3]; 00254 scol= scolmain+4*mface->v3; 00255 mcol[9]= scol[1]; mcol[10]= scol[2]; mcol[11]= scol[3]; 00256 if(mface->v4) { 00257 scol= scolmain+4*mface->v4; 00258 mcol[13]= scol[1]; mcol[14]= scol[2]; mcol[15]= scol[3]; 00259 } 00260 } 00261 if(tface) tface++; 00262 } 00263 00264 MEM_freeN(scolmain); 00265 } 00266 00267 static void make_vertexcol(Object *ob) /* single ob */ 00268 { 00269 Mesh *me; 00270 if(!ob || ob->id.lib) return; 00271 me= get_mesh(ob); 00272 if(me==NULL) return; 00273 if(me->edit_mesh) return; 00274 00275 /* copies from shadedisplist to mcol */ 00276 if(!me->mcol) { 00277 CustomData_add_layer(&me->fdata, CD_MCOL, CD_CALLOC, NULL, me->totface); 00278 mesh_update_customdata_pointers(me); 00279 } 00280 00281 //if(shade) 00282 // shadeMeshMCol(scene, ob, me); 00283 //else 00284 00285 memset(me->mcol, 255, 4*sizeof(MCol)*me->totface); 00286 00287 DAG_id_tag_update(&me->id, 0); 00288 00289 } 00290 00291 /* mirror_vgroup is set to -1 when invalid */ 00292 static void wpaint_mirror_vgroup_ensure(Object *ob, int *vgroup_mirror) 00293 { 00294 bDeformGroup *defgroup= BLI_findlink(&ob->defbase, ob->actdef - 1); 00295 00296 if(defgroup) { 00297 bDeformGroup *curdef; 00298 int mirrdef; 00299 char name[MAXBONENAME]; 00300 00301 flip_side_name(name, defgroup->name, FALSE); 00302 00303 if(strcmp(name, defgroup->name) != 0) { 00304 for (curdef= ob->defbase.first, mirrdef= 0; curdef; curdef=curdef->next, mirrdef++) { 00305 if (!strcmp(curdef->name, name)) { 00306 break; 00307 } 00308 } 00309 00310 if(curdef==NULL) { 00311 int olddef= ob->actdef; /* tsk, ED_vgroup_add sets the active defgroup */ 00312 curdef= ED_vgroup_add_name(ob, name); 00313 ob->actdef= olddef; 00314 } 00315 00316 /* curdef should never be NULL unless this is 00317 * a lamp and ED_vgroup_add_name fails */ 00318 if(curdef) { 00319 *vgroup_mirror= mirrdef; 00320 return; 00321 } 00322 } 00323 } 00324 00325 *vgroup_mirror= -1; 00326 } 00327 00328 static void copy_vpaint_prev(VPaint *vp, unsigned int *mcol, int tot) 00329 { 00330 if(vp->vpaint_prev) { 00331 MEM_freeN(vp->vpaint_prev); 00332 vp->vpaint_prev= NULL; 00333 } 00334 vp->tot= tot; 00335 00336 if(mcol==NULL || tot==0) return; 00337 00338 vp->vpaint_prev= MEM_mallocN(4*sizeof(int)*tot, "vpaint_prev"); 00339 memcpy(vp->vpaint_prev, mcol, 4*sizeof(int)*tot); 00340 00341 } 00342 00343 static void copy_wpaint_prev (VPaint *wp, MDeformVert *dverts, int dcount) 00344 { 00345 if (wp->wpaint_prev) { 00346 free_dverts(wp->wpaint_prev, wp->tot); 00347 wp->wpaint_prev= NULL; 00348 } 00349 00350 if(dverts && dcount) { 00351 00352 wp->wpaint_prev = MEM_mallocN (sizeof(MDeformVert)*dcount, "wpaint prev"); 00353 wp->tot = dcount; 00354 copy_dverts (wp->wpaint_prev, dverts, dcount); 00355 } 00356 } 00357 00358 00359 void vpaint_fill(Object *ob, unsigned int paintcol) 00360 { 00361 Mesh *me; 00362 MFace *mf; 00363 unsigned int *mcol; 00364 int i, selected; 00365 00366 me= get_mesh(ob); 00367 if(me==NULL || me->totface==0) return; 00368 00369 if(!me->mcol) 00370 make_vertexcol(ob); 00371 00372 selected= (me->editflag & ME_EDIT_PAINT_MASK); 00373 00374 mf = me->mface; 00375 mcol = (unsigned int*)me->mcol; 00376 for (i = 0; i < me->totface; i++, mf++, mcol+=4) { 00377 if (!selected || mf->flag & ME_FACE_SEL) { 00378 mcol[0] = paintcol; 00379 mcol[1] = paintcol; 00380 mcol[2] = paintcol; 00381 mcol[3] = paintcol; 00382 } 00383 } 00384 00385 DAG_id_tag_update(&me->id, 0); 00386 } 00387 00388 00389 /* fills in the selected faces with the current weight and vertex group */ 00390 void wpaint_fill(VPaint *wp, Object *ob, float paintweight) 00391 { 00392 Mesh *me; 00393 MFace *mface; 00394 MDeformWeight *dw, *uw; 00395 int *indexar; 00396 int index, vgroup; 00397 unsigned int faceverts[5]={0,0,0,0,0}; 00398 unsigned char i; 00399 int vgroup_mirror= -1; 00400 int selected; 00401 00402 me= ob->data; 00403 if(me==NULL || me->totface==0 || me->dvert==NULL || !me->mface) return; 00404 00405 selected= (me->editflag & ME_EDIT_PAINT_MASK); 00406 00407 indexar= get_indexarray(me); 00408 00409 if(selected) { 00410 for(index=0, mface=me->mface; index<me->totface; index++, mface++) { 00411 if((mface->flag & ME_FACE_SEL)==0) 00412 indexar[index]= 0; 00413 else 00414 indexar[index]= index+1; 00415 } 00416 } 00417 else { 00418 for(index=0; index<me->totface; index++) 00419 indexar[index]= index+1; 00420 } 00421 00422 vgroup= ob->actdef-1; 00423 00424 /* if mirror painting, find the other group */ 00425 if(me->editflag & ME_EDIT_MIRROR_X) { 00426 wpaint_mirror_vgroup_ensure(ob, &vgroup_mirror); 00427 } 00428 00429 copy_wpaint_prev(wp, me->dvert, me->totvert); 00430 00431 for(index=0; index<me->totface; index++) { 00432 if(indexar[index] && indexar[index]<=me->totface) { 00433 mface= me->mface + (indexar[index]-1); 00434 /* just so we can loop through the verts */ 00435 faceverts[0]= mface->v1; 00436 faceverts[1]= mface->v2; 00437 faceverts[2]= mface->v3; 00438 faceverts[3]= mface->v4; 00439 for (i=0; i<3 || faceverts[i]; i++) { 00440 if(!((me->dvert+faceverts[i])->flag)) { 00441 dw= defvert_verify_index(me->dvert+faceverts[i], vgroup); 00442 if(dw) { 00443 uw= defvert_verify_index(wp->wpaint_prev+faceverts[i], vgroup); 00444 uw->weight= dw->weight; /* set the undo weight */ 00445 dw->weight= paintweight; 00446 00447 if(me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */ 00448 int j= mesh_get_x_mirror_vert(ob, faceverts[i]); 00449 if(j>=0) { 00450 /* copy, not paint again */ 00451 if(vgroup_mirror != -1) { 00452 dw= defvert_verify_index(me->dvert+j, vgroup_mirror); 00453 uw= defvert_verify_index(wp->wpaint_prev+j, vgroup_mirror); 00454 } else { 00455 dw= defvert_verify_index(me->dvert+j, vgroup); 00456 uw= defvert_verify_index(wp->wpaint_prev+j, vgroup); 00457 } 00458 uw->weight= dw->weight; /* set the undo weight */ 00459 dw->weight= paintweight; 00460 } 00461 } 00462 } 00463 (me->dvert+faceverts[i])->flag= 1; 00464 } 00465 } 00466 } 00467 } 00468 00469 index=0; 00470 while (index<me->totvert) { 00471 (me->dvert+index)->flag= 0; 00472 index++; 00473 } 00474 00475 MEM_freeN(indexar); 00476 copy_wpaint_prev(wp, NULL, 0); 00477 00478 DAG_id_tag_update(&me->id, 0); 00479 } 00480 00481 /* XXX: should be re-implemented as a vertex/weight paint 'color correct' operator 00482 00483 void vpaint_dogamma(Scene *scene) 00484 { 00485 VPaint *vp= scene->toolsettings->vpaint; 00486 Mesh *me; 00487 Object *ob; 00488 float igam, fac; 00489 int a, temp; 00490 unsigned char *cp, gamtab[256]; 00491 00492 ob= OBACT; 00493 me= get_mesh(ob); 00494 00495 if(!(ob->mode & OB_MODE_VERTEX_PAINT)) return; 00496 if(me==0 || me->mcol==0 || me->totface==0) return; 00497 00498 igam= 1.0/vp->gamma; 00499 for(a=0; a<256; a++) { 00500 00501 fac= ((float)a)/255.0; 00502 fac= vp->mul*pow( fac, igam); 00503 00504 temp= 255.9*fac; 00505 00506 if(temp<=0) gamtab[a]= 0; 00507 else if(temp>=255) gamtab[a]= 255; 00508 else gamtab[a]= temp; 00509 } 00510 00511 a= 4*me->totface; 00512 cp= (unsigned char *)me->mcol; 00513 while(a--) { 00514 00515 cp[1]= gamtab[ cp[1] ]; 00516 cp[2]= gamtab[ cp[2] ]; 00517 cp[3]= gamtab[ cp[3] ]; 00518 00519 cp+= 4; 00520 } 00521 } 00522 */ 00523 00524 static unsigned int mcol_blend(unsigned int col1, unsigned int col2, int fac) 00525 { 00526 char *cp1, *cp2, *cp; 00527 int mfac; 00528 unsigned int col=0; 00529 00530 if(fac==0) return col1; 00531 if(fac>=255) return col2; 00532 00533 mfac= 255-fac; 00534 00535 cp1= (char *)&col1; 00536 cp2= (char *)&col2; 00537 cp= (char *)&col; 00538 00539 cp[0]= 255; 00540 cp[1]= (mfac*cp1[1]+fac*cp2[1])/255; 00541 cp[2]= (mfac*cp1[2]+fac*cp2[2])/255; 00542 cp[3]= (mfac*cp1[3]+fac*cp2[3])/255; 00543 00544 return col; 00545 } 00546 00547 static unsigned int mcol_add(unsigned int col1, unsigned int col2, int fac) 00548 { 00549 char *cp1, *cp2, *cp; 00550 int temp; 00551 unsigned int col=0; 00552 00553 if(fac==0) return col1; 00554 00555 cp1= (char *)&col1; 00556 cp2= (char *)&col2; 00557 cp= (char *)&col; 00558 00559 cp[0]= 255; 00560 temp= cp1[1] + ((fac*cp2[1])/255); 00561 if(temp>254) cp[1]= 255; else cp[1]= temp; 00562 temp= cp1[2] + ((fac*cp2[2])/255); 00563 if(temp>254) cp[2]= 255; else cp[2]= temp; 00564 temp= cp1[3] + ((fac*cp2[3])/255); 00565 if(temp>254) cp[3]= 255; else cp[3]= temp; 00566 00567 return col; 00568 } 00569 00570 static unsigned int mcol_sub(unsigned int col1, unsigned int col2, int fac) 00571 { 00572 char *cp1, *cp2, *cp; 00573 int temp; 00574 unsigned int col=0; 00575 00576 if(fac==0) return col1; 00577 00578 cp1= (char *)&col1; 00579 cp2= (char *)&col2; 00580 cp= (char *)&col; 00581 00582 cp[0]= 255; 00583 temp= cp1[1] - ((fac*cp2[1])/255); 00584 if(temp<0) cp[1]= 0; else cp[1]= temp; 00585 temp= cp1[2] - ((fac*cp2[2])/255); 00586 if(temp<0) cp[2]= 0; else cp[2]= temp; 00587 temp= cp1[3] - ((fac*cp2[3])/255); 00588 if(temp<0) cp[3]= 0; else cp[3]= temp; 00589 00590 return col; 00591 } 00592 00593 static unsigned int mcol_mul(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 00601 mfac= 255-fac; 00602 00603 cp1= (char *)&col1; 00604 cp2= (char *)&col2; 00605 cp= (char *)&col; 00606 00607 /* first mul, then blend the fac */ 00608 cp[0]= 255; 00609 cp[1]= (mfac*cp1[1] + fac*((cp2[1]*cp1[1])/255) )/255; 00610 cp[2]= (mfac*cp1[2] + fac*((cp2[2]*cp1[2])/255) )/255; 00611 cp[3]= (mfac*cp1[3] + fac*((cp2[3]*cp1[3])/255) )/255; 00612 00613 00614 return col; 00615 } 00616 00617 static unsigned int mcol_lighten(unsigned int col1, unsigned int col2, int fac) 00618 { 00619 char *cp1, *cp2, *cp; 00620 int mfac; 00621 unsigned int col=0; 00622 00623 if(fac==0) return col1; 00624 if(fac>=255) return col2; 00625 00626 mfac= 255-fac; 00627 00628 cp1= (char *)&col1; 00629 cp2= (char *)&col2; 00630 cp= (char *)&col; 00631 00632 /* See if are lighter, if so mix, else dont do anything. 00633 if the paint col is darker then the original, then ignore */ 00634 if (cp1[1]+cp1[2]+cp1[3] > cp2[1]+cp2[2]+cp2[3]) 00635 return col1; 00636 00637 cp[0]= 255; 00638 cp[1]= (mfac*cp1[1]+fac*cp2[1])/255; 00639 cp[2]= (mfac*cp1[2]+fac*cp2[2])/255; 00640 cp[3]= (mfac*cp1[3]+fac*cp2[3])/255; 00641 00642 return col; 00643 } 00644 00645 static unsigned int mcol_darken(unsigned int col1, unsigned int col2, int fac) 00646 { 00647 char *cp1, *cp2, *cp; 00648 int mfac; 00649 unsigned int col=0; 00650 00651 if(fac==0) return col1; 00652 if(fac>=255) return col2; 00653 00654 mfac= 255-fac; 00655 00656 cp1= (char *)&col1; 00657 cp2= (char *)&col2; 00658 cp= (char *)&col; 00659 00660 /* See if were darker, if so mix, else dont do anything. 00661 if the paint col is brighter then the original, then ignore */ 00662 if (cp1[1]+cp1[2]+cp1[3] < cp2[1]+cp2[2]+cp2[3]) 00663 return col1; 00664 00665 cp[0]= 255; 00666 cp[1]= (mfac*cp1[1]+fac*cp2[1])/255; 00667 cp[2]= (mfac*cp1[2]+fac*cp2[2])/255; 00668 cp[3]= (mfac*cp1[3]+fac*cp2[3])/255; 00669 return col; 00670 } 00671 00672 static void vpaint_blend(VPaint *vp, unsigned int *col, unsigned int *colorig, unsigned int paintcol, int alpha) 00673 { 00674 Brush *brush = paint_brush(&vp->paint); 00675 00676 if(brush->vertexpaint_tool==VP_MIX || brush->vertexpaint_tool==VP_BLUR) *col= mcol_blend( *col, paintcol, alpha); 00677 else if(brush->vertexpaint_tool==VP_ADD) *col= mcol_add( *col, paintcol, alpha); 00678 else if(brush->vertexpaint_tool==VP_SUB) *col= mcol_sub( *col, paintcol, alpha); 00679 else if(brush->vertexpaint_tool==VP_MUL) *col= mcol_mul( *col, paintcol, alpha); 00680 else if(brush->vertexpaint_tool==VP_LIGHTEN) *col= mcol_lighten( *col, paintcol, alpha); 00681 else if(brush->vertexpaint_tool==VP_DARKEN) *col= mcol_darken( *col, paintcol, alpha); 00682 00683 /* if no spray, clip color adding with colorig & orig alpha */ 00684 if((vp->flag & VP_SPRAY)==0) { 00685 unsigned int testcol=0, a; 00686 char *cp, *ct, *co; 00687 00688 alpha= (int)(255.0f*brush_alpha(brush)); 00689 00690 if(brush->vertexpaint_tool==VP_MIX || brush->vertexpaint_tool==VP_BLUR) testcol= mcol_blend( *colorig, paintcol, alpha); 00691 else if(brush->vertexpaint_tool==VP_ADD) testcol= mcol_add( *colorig, paintcol, alpha); 00692 else if(brush->vertexpaint_tool==VP_SUB) testcol= mcol_sub( *colorig, paintcol, alpha); 00693 else if(brush->vertexpaint_tool==VP_MUL) testcol= mcol_mul( *colorig, paintcol, alpha); 00694 else if(brush->vertexpaint_tool==VP_LIGHTEN) testcol= mcol_lighten( *colorig, paintcol, alpha); 00695 else if(brush->vertexpaint_tool==VP_DARKEN) testcol= mcol_darken( *colorig, paintcol, alpha); 00696 00697 cp= (char *)col; 00698 ct= (char *)&testcol; 00699 co= (char *)colorig; 00700 00701 for(a=0; a<4; a++) { 00702 if( ct[a]<co[a] ) { 00703 if( cp[a]<ct[a] ) cp[a]= ct[a]; 00704 else if( cp[a]>co[a] ) cp[a]= co[a]; 00705 } 00706 else { 00707 if( cp[a]<co[a] ) cp[a]= co[a]; 00708 else if( cp[a]>ct[a] ) cp[a]= ct[a]; 00709 } 00710 } 00711 } 00712 } 00713 00714 00715 static int sample_backbuf_area(ViewContext *vc, int *indexar, int totface, int x, int y, float size) 00716 { 00717 struct ImBuf *ibuf; 00718 int a, tot=0, index; 00719 00720 /* brecht: disabled this because it obviously failes for 00721 brushes with size > 64, why is this here? */ 00722 /*if(size>64.0) size= 64.0;*/ 00723 00724 ibuf= view3d_read_backbuf(vc, x-size, y-size, x+size, y+size); 00725 if(ibuf) { 00726 unsigned int *rt= ibuf->rect; 00727 00728 memset(indexar, 0, sizeof(int)*(totface+1)); 00729 00730 size= ibuf->x*ibuf->y; 00731 while(size--) { 00732 00733 if(*rt) { 00734 index= WM_framebuffer_to_index(*rt); 00735 if(index>0 && index<=totface) 00736 indexar[index] = 1; 00737 } 00738 00739 rt++; 00740 } 00741 00742 for(a=1; a<=totface; a++) { 00743 if(indexar[a]) indexar[tot++]= a; 00744 } 00745 00746 IMB_freeImBuf(ibuf); 00747 } 00748 00749 return tot; 00750 } 00751 00752 static float calc_vp_alpha_dl(VPaint *vp, ViewContext *vc, float vpimat[][3], float *vert_nor, const float mval[2], float pressure) 00753 { 00754 Brush *brush = paint_brush(&vp->paint); 00755 float fac, fac_2, size, dx, dy; 00756 float alpha; 00757 int vertco[2]; 00758 const int radius= brush_size(brush); 00759 00760 project_int_noclip(vc->ar, vert_nor, vertco); 00761 dx= mval[0]-vertco[0]; 00762 dy= mval[1]-vertco[1]; 00763 00764 if (brush_use_size_pressure(brush)) 00765 size = pressure * radius; 00766 else 00767 size = radius; 00768 00769 fac_2= dx*dx + dy*dy; 00770 if(fac_2 > size*size) return 0.f; 00771 fac = sqrtf(fac_2); 00772 00773 alpha= brush_alpha(brush) * brush_curve_strength_clamp(brush, fac, size); 00774 00775 if (brush_use_alpha_pressure(brush)) 00776 alpha *= pressure; 00777 00778 if(vp->flag & VP_NORMALS) { 00779 float *no= vert_nor+3; 00780 00781 /* transpose ! */ 00782 fac= vpimat[2][0]*no[0]+vpimat[2][1]*no[1]+vpimat[2][2]*no[2]; 00783 if(fac > 0.0f) { 00784 dx= vpimat[0][0]*no[0]+vpimat[0][1]*no[1]+vpimat[0][2]*no[2]; 00785 dy= vpimat[1][0]*no[0]+vpimat[1][1]*no[1]+vpimat[1][2]*no[2]; 00786 00787 alpha*= fac/sqrtf(dx*dx + dy*dy + fac*fac); 00788 } 00789 else return 0.f; 00790 } 00791 00792 return alpha; 00793 } 00794 00795 static void wpaint_blend(VPaint *wp, MDeformWeight *dw, MDeformWeight *uw, float alpha, float paintval, int flip) 00796 { 00797 Brush *brush = paint_brush(&wp->paint); 00798 int tool = brush->vertexpaint_tool; 00799 00800 if(dw==NULL || uw==NULL) return; 00801 00802 if (flip) { 00803 switch(tool) { 00804 case VP_MIX: 00805 paintval = 1.f - paintval; break; 00806 case VP_ADD: 00807 tool= VP_SUB; break; 00808 case VP_SUB: 00809 tool= VP_ADD; break; 00810 case VP_LIGHTEN: 00811 tool= VP_DARKEN; break; 00812 case VP_DARKEN: 00813 tool= VP_LIGHTEN; break; 00814 } 00815 } 00816 00817 if(tool==VP_MIX || tool==VP_BLUR) 00818 dw->weight = paintval*alpha + dw->weight*(1.0f-alpha); 00819 else if(tool==VP_ADD) 00820 dw->weight += paintval*alpha; 00821 else if(tool==VP_SUB) 00822 dw->weight -= paintval*alpha; 00823 else if(tool==VP_MUL) 00824 /* first mul, then blend the fac */ 00825 dw->weight = ((1.0f-alpha) + alpha*paintval)*dw->weight; 00826 else if(tool==VP_LIGHTEN) { 00827 if (dw->weight < paintval) 00828 dw->weight = paintval*alpha + dw->weight*(1.0f-alpha); 00829 } else if(tool==VP_DARKEN) { 00830 if (dw->weight > paintval) 00831 dw->weight = paintval*alpha + dw->weight*(1.0f-alpha); 00832 } 00833 CLAMP(dw->weight, 0.0f, 1.0f); 00834 00835 /* if no spray, clip result with orig weight & orig alpha */ 00836 if((wp->flag & VP_SPRAY)==0) { 00837 float testw=0.0f; 00838 00839 alpha= brush_alpha(brush); 00840 if(tool==VP_MIX || tool==VP_BLUR) 00841 testw = paintval*alpha + uw->weight*(1.0f-alpha); 00842 else if(tool==VP_ADD) 00843 testw = uw->weight + paintval*alpha; 00844 else if(tool==VP_SUB) 00845 testw = uw->weight - paintval*alpha; 00846 else if(tool==VP_MUL) 00847 /* first mul, then blend the fac */ 00848 testw = ((1.0f-alpha) + alpha*paintval)*uw->weight; 00849 else if(tool==VP_LIGHTEN) { 00850 if (uw->weight < paintval) 00851 testw = paintval*alpha + uw->weight*(1.0f-alpha); 00852 else 00853 testw = uw->weight; 00854 } else if(tool==VP_DARKEN) { 00855 if (uw->weight > paintval) 00856 testw = paintval*alpha + uw->weight*(1.0f-alpha); 00857 else 00858 testw = uw->weight; 00859 } 00860 CLAMP(testw, 0.0f, 1.0f); 00861 00862 if( testw<uw->weight ) { 00863 if(dw->weight < testw) dw->weight= testw; 00864 else if(dw->weight > uw->weight) dw->weight= uw->weight; 00865 } 00866 else { 00867 if(dw->weight > testw) dw->weight= testw; 00868 else if(dw->weight < uw->weight) dw->weight= uw->weight; 00869 } 00870 } 00871 00872 } 00873 00874 /* ----------------------------------------------------- */ 00875 00876 00877 /* sets wp->weight to the closest weight value to vertex */ 00878 /* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */ 00879 static int weight_sample_invoke(bContext *C, wmOperator *op, wmEvent *event) 00880 { 00881 ViewContext vc; 00882 Mesh *me; 00883 short change= FALSE; 00884 00885 view3d_set_viewcontext(C, &vc); 00886 me= get_mesh(vc.obact); 00887 00888 if (me && me->dvert && vc.v3d && vc.rv3d) { 00889 int index; 00890 00891 view3d_operator_needs_opengl(C); 00892 00893 index= view3d_sample_backbuf(&vc, event->mval[0], event->mval[1]); 00894 00895 if(index && index<=me->totface) { 00896 DerivedMesh *dm= mesh_get_derived_final(vc.scene, vc.obact, CD_MASK_BAREMESH); 00897 00898 if(dm->getVertCo==NULL) { 00899 BKE_report(op->reports, RPT_WARNING, "The modifier used does not support deformed locations"); 00900 } 00901 else { 00902 MFace *mf= ((MFace *)me->mface) + index-1; 00903 const int vgroup= vc.obact->actdef - 1; 00904 ToolSettings *ts= vc.scene->toolsettings; 00905 float mval_f[2]; 00906 int v_idx_best= -1; 00907 int fidx; 00908 float len_best= FLT_MAX; 00909 00910 mval_f[0]= (float)event->mval[0]; 00911 mval_f[1]= (float)event->mval[1]; 00912 00913 fidx= mf->v4 ? 3:2; 00914 do { 00915 float co[3], sco[3], len; 00916 const int v_idx= (*(&mf->v1 + fidx)); 00917 dm->getVertCo(dm, v_idx, co); 00918 project_float_noclip(vc.ar, co, sco); 00919 len= len_squared_v2v2(mval_f, sco); 00920 if(len < len_best) { 00921 len_best= len; 00922 v_idx_best= v_idx; 00923 } 00924 } while (fidx--); 00925 00926 if(v_idx_best != -1) { /* should always be valid */ 00927 ts->vgroup_weight= defvert_find_weight(&me->dvert[v_idx_best], vgroup); 00928 change= TRUE; 00929 } 00930 } 00931 dm->release(dm); 00932 } 00933 } 00934 00935 if(change) { 00936 /* not really correct since the brush didnt change, but redraws the toolbar */ 00937 WM_main_add_notifier(NC_BRUSH|NA_EDITED, NULL); /* ts->wpaint->paint.brush */ 00938 00939 return OPERATOR_FINISHED; 00940 } 00941 else { 00942 return OPERATOR_CANCELLED; 00943 } 00944 } 00945 00946 void PAINT_OT_weight_sample(wmOperatorType *ot) 00947 { 00948 /* identifiers */ 00949 ot->name= "Weight Paint Sample Weight"; 00950 ot->idname= "PAINT_OT_weight_sample"; 00951 00952 /* api callbacks */ 00953 ot->invoke= weight_sample_invoke; 00954 ot->poll= weight_paint_mode_poll; 00955 00956 /* flags */ 00957 ot->flag= OPTYPE_UNDO; 00958 } 00959 00960 /* samples cursor location, and gives menu with vertex groups to activate */ 00961 static EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) 00962 { 00963 if (C) { 00964 wmWindow *win= CTX_wm_window(C); 00965 if(win && win->eventstate) { 00966 ViewContext vc; 00967 Mesh *me; 00968 00969 view3d_set_viewcontext(C, &vc); 00970 me= get_mesh(vc.obact); 00971 00972 if (me && me->dvert && vc.v3d && vc.rv3d) { 00973 int index; 00974 00975 view3d_operator_needs_opengl(C); 00976 00977 index= view3d_sample_backbuf(&vc, win->eventstate->x - vc.ar->winrct.xmin, win->eventstate->y - vc.ar->winrct.ymin); 00978 00979 if(index && index<=me->totface) { 00980 const int totgroup= BLI_countlist(&vc.obact->defbase); 00981 if(totgroup) { 00982 MFace *mf= ((MFace *)me->mface) + index-1; 00983 int fidx= mf->v4 ? 3:2; 00984 int *groups= MEM_callocN(totgroup*sizeof(int), "groups"); 00985 int found= FALSE; 00986 00987 do { 00988 MDeformVert *dvert= me->dvert + (*(&mf->v1 + fidx)); 00989 int i= dvert->totweight; 00990 MDeformWeight *dw; 00991 for(dw= dvert->dw; i > 0; dw++, i--) { 00992 groups[dw->def_nr]= TRUE; 00993 found= TRUE; 00994 } 00995 } while (fidx--); 00996 00997 if(found==FALSE) { 00998 MEM_freeN(groups); 00999 } 01000 else { 01001 EnumPropertyItem *item= NULL, item_tmp= {0}; 01002 int totitem= 0; 01003 int i= 0; 01004 bDeformGroup *dg; 01005 for(dg= vc.obact->defbase.first; dg && i<totgroup; i++, dg= dg->next) { 01006 if(groups[i]) { 01007 item_tmp.identifier= item_tmp.name= dg->name; 01008 item_tmp.value= i; 01009 RNA_enum_item_add(&item, &totitem, &item_tmp); 01010 } 01011 } 01012 01013 RNA_enum_item_end(&item, &totitem); 01014 *free= 1; 01015 01016 MEM_freeN(groups); 01017 return item; 01018 } 01019 } 01020 } 01021 } 01022 } 01023 } 01024 01025 return DummyRNA_NULL_items; 01026 } 01027 01028 static int weight_sample_group_exec(bContext *C, wmOperator *op) 01029 { 01030 int type= RNA_enum_get(op->ptr, "group"); 01031 ViewContext vc; 01032 view3d_set_viewcontext(C, &vc); 01033 01034 vc.obact->actdef= type + 1; 01035 01036 DAG_id_tag_update(&vc.obact->id, OB_RECALC_DATA); 01037 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, vc.obact); 01038 return OPERATOR_FINISHED; 01039 } 01040 01041 /* TODO, we could make this a menu into OBJECT_OT_vertex_group_set_active rather than its own operator */ 01042 void PAINT_OT_weight_sample_group(wmOperatorType *ot) 01043 { 01044 PropertyRNA *prop= NULL; 01045 01046 /* identifiers */ 01047 ot->name= "Weight Paint Sample Group"; 01048 ot->idname= "PAINT_OT_weight_sample_group"; 01049 01050 /* api callbacks */ 01051 ot->exec= weight_sample_group_exec; 01052 ot->invoke= WM_menu_invoke; 01053 ot->poll= weight_paint_mode_poll; 01054 01055 /* flags */ 01056 ot->flag= OPTYPE_UNDO; 01057 01058 /* keyingset to use (dynamic enum) */ 01059 prop= RNA_def_enum(ot->srna, "group", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); 01060 RNA_def_enum_funcs(prop, weight_paint_sample_enum_itemf); 01061 ot->prop= prop; 01062 } 01063 01064 01065 static void do_weight_paint_auto_normalize(MDeformVert *dvert, 01066 int paint_nr, char *map) 01067 { 01068 // MDeformWeight *dw = dvert->dw; 01069 float sum=0.0f, fac=0.0f, paintw=0.0f; 01070 int i, tot=0; 01071 01072 if (!map) 01073 return; 01074 01075 for (i=0; i<dvert->totweight; i++) { 01076 if (dvert->dw[i].def_nr == paint_nr) 01077 paintw = dvert->dw[i].weight; 01078 01079 if (map[dvert->dw[i].def_nr]) { 01080 tot += 1; 01081 if (dvert->dw[i].def_nr != paint_nr) 01082 sum += dvert->dw[i].weight; 01083 } 01084 } 01085 01086 if (!tot || sum <= (1.0f - paintw)) 01087 return; 01088 01089 fac = sum / (1.0f - paintw); 01090 fac = fac==0.0f ? 1.0f : 1.0f / fac; 01091 01092 for (i=0; i<dvert->totweight; i++) { 01093 if (map[dvert->dw[i].def_nr]) { 01094 if (dvert->dw[i].def_nr != paint_nr) 01095 dvert->dw[i].weight *= fac; 01096 } 01097 } 01098 } 01099 01100 static void do_weight_paint_vertex(VPaint *wp, Object *ob, int index, 01101 float alpha, float paintweight, int flip, 01102 int vgroup_mirror, char *validmap) 01103 { 01104 Mesh *me= ob->data; 01105 MDeformWeight *dw, *uw; 01106 int vgroup= ob->actdef-1; 01107 01108 if(wp->flag & VP_ONLYVGROUP) { 01109 dw= defvert_find_index(me->dvert+index, vgroup); 01110 uw= defvert_find_index(wp->wpaint_prev+index, vgroup); 01111 } 01112 else { 01113 dw= defvert_verify_index(me->dvert+index, vgroup); 01114 uw= defvert_verify_index(wp->wpaint_prev+index, vgroup); 01115 } 01116 if(dw==NULL || uw==NULL) 01117 return; 01118 01119 wpaint_blend(wp, dw, uw, alpha, paintweight, flip); 01120 do_weight_paint_auto_normalize(me->dvert+index, vgroup, validmap); 01121 01122 if(me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */ 01123 int j= mesh_get_x_mirror_vert(ob, index); 01124 if(j>=0) { 01125 /* copy, not paint again */ 01126 if(vgroup_mirror != -1) 01127 uw= defvert_verify_index(me->dvert+j, vgroup_mirror); 01128 else 01129 uw= defvert_verify_index(me->dvert+j, vgroup); 01130 01131 uw->weight= dw->weight; 01132 01133 do_weight_paint_auto_normalize(me->dvert+j, vgroup, validmap); 01134 } 01135 } 01136 } 01137 01138 01139 /* *************** set wpaint operator ****************** */ 01140 01141 static int set_wpaint(bContext *C, wmOperator *UNUSED(op)) /* toggle */ 01142 { 01143 Object *ob= CTX_data_active_object(C); 01144 Scene *scene= CTX_data_scene(C); 01145 VPaint *wp= scene->toolsettings->wpaint; 01146 Mesh *me; 01147 01148 me= get_mesh(ob); 01149 if(ob->id.lib || me==NULL) return OPERATOR_PASS_THROUGH; 01150 01151 if(ob->mode & OB_MODE_WEIGHT_PAINT) ob->mode &= ~OB_MODE_WEIGHT_PAINT; 01152 else ob->mode |= OB_MODE_WEIGHT_PAINT; 01153 01154 01155 /* Weightpaint works by overriding colors in mesh, 01156 * so need to make sure we recalc on enter and 01157 * exit (exit needs doing regardless because we 01158 * should redeform). 01159 */ 01160 DAG_id_tag_update(&me->id, 0); 01161 01162 if(ob->mode & OB_MODE_WEIGHT_PAINT) { 01163 Object *par; 01164 01165 if(wp==NULL) 01166 wp= scene->toolsettings->wpaint= new_vpaint(1); 01167 01168 paint_init(&wp->paint, PAINT_CURSOR_WEIGHT_PAINT); 01169 paint_cursor_start(C, weight_paint_poll); 01170 01171 mesh_octree_table(ob, NULL, NULL, 's'); 01172 01173 /* verify if active weight group is also active bone */ 01174 par= modifiers_isDeformedByArmature(ob); 01175 if(par && (par->mode & OB_MODE_POSE)) { 01176 bArmature *arm= par->data; 01177 01178 if(arm->act_bone) 01179 ED_vgroup_select_by_name(ob, arm->act_bone->name); 01180 } 01181 } 01182 else { 01183 mesh_octree_table(NULL, NULL, NULL, 'e'); 01184 mesh_mirrtopo_table(NULL, 'e'); 01185 } 01186 01187 WM_event_add_notifier(C, NC_SCENE|ND_MODE, scene); 01188 01189 return OPERATOR_FINISHED; 01190 } 01191 01192 /* for switching to/from mode */ 01193 static int paint_poll_test(bContext *C) 01194 { 01195 if(CTX_data_edit_object(C)) 01196 return 0; 01197 if(CTX_data_active_object(C)==NULL) 01198 return 0; 01199 return 1; 01200 } 01201 01202 void PAINT_OT_weight_paint_toggle(wmOperatorType *ot) 01203 { 01204 01205 /* identifiers */ 01206 ot->name= "Weight Paint Mode"; 01207 ot->idname= "PAINT_OT_weight_paint_toggle"; 01208 01209 /* api callbacks */ 01210 ot->exec= set_wpaint; 01211 ot->poll= paint_poll_test; 01212 01213 /* flags */ 01214 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01215 01216 } 01217 01218 /* ************ weight paint operator ********** */ 01219 01220 struct WPaintData { 01221 ViewContext vc; 01222 int *indexar; 01223 int vgroup_mirror; 01224 float *vertexcosnos; 01225 float wpimat[3][3]; 01226 01227 /*variables for auto normalize*/ 01228 int auto_normalize; 01229 char *vgroup_validmap; /*stores if vgroups tie to deforming bones or not*/ 01230 }; 01231 01232 static char *wpaint_make_validmap(Object *ob) 01233 { 01234 bDeformGroup *dg; 01235 ModifierData *md; 01236 char *validmap; 01237 bPose *pose; 01238 bPoseChannel *chan; 01239 ArmatureModifierData *amd; 01240 GHash *gh = BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "wpaint_make_validmap gh"); 01241 int i = 0, step1=1; 01242 01243 /*add all names to a hash table*/ 01244 for (dg=ob->defbase.first, i=0; dg; dg=dg->next, i++) { 01245 BLI_ghash_insert(gh, dg->name, NULL); 01246 } 01247 01248 if (!i) 01249 return NULL; 01250 01251 validmap = MEM_callocN(i, "wpaint valid map"); 01252 01253 /*now loop through the armature modifiers and identify deform bones*/ 01254 for (md = ob->modifiers.first; md; md= !md->next && step1 ? (step1=0), modifiers_getVirtualModifierList(ob) : md->next) { 01255 if (!(md->mode & (eModifierMode_Realtime|eModifierMode_Virtual))) 01256 continue; 01257 01258 if (md->type == eModifierType_Armature) 01259 { 01260 amd = (ArmatureModifierData*) md; 01261 01262 if(amd->object && amd->object->pose) { 01263 pose = amd->object->pose; 01264 01265 for (chan=pose->chanbase.first; chan; chan=chan->next) { 01266 if (chan->bone->flag & BONE_NO_DEFORM) 01267 continue; 01268 01269 if (BLI_ghash_haskey(gh, chan->name)) { 01270 BLI_ghash_remove(gh, chan->name, NULL, NULL); 01271 BLI_ghash_insert(gh, chan->name, SET_INT_IN_POINTER(1)); 01272 } 01273 } 01274 } 01275 } 01276 } 01277 01278 /*add all names to a hash table*/ 01279 for (dg=ob->defbase.first, i=0; dg; dg=dg->next, i++) { 01280 if (BLI_ghash_lookup(gh, dg->name) != NULL) { 01281 validmap[i] = 1; 01282 } 01283 } 01284 01285 BLI_ghash_free(gh, NULL, NULL); 01286 01287 return validmap; 01288 } 01289 01290 static int wpaint_stroke_test_start(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 01291 { 01292 Scene *scene= CTX_data_scene(C); 01293 struct PaintStroke *stroke = op->customdata; 01294 ToolSettings *ts= CTX_data_tool_settings(C); 01295 VPaint *wp= ts->wpaint; 01296 Object *ob= CTX_data_active_object(C); 01297 struct WPaintData *wpd; 01298 Mesh *me; 01299 float mat[4][4], imat[4][4]; 01300 01301 if(scene->obedit) return OPERATOR_CANCELLED; 01302 01303 me= get_mesh(ob); 01304 if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH; 01305 01306 /* if nothing was added yet, we make dverts and a vertex deform group */ 01307 if (!me->dvert) { 01308 ED_vgroup_data_create(&me->id); 01309 WM_event_add_notifier(C, NC_GEOM|ND_DATA, me); 01310 } 01311 01312 /* make mode data storage */ 01313 wpd= MEM_callocN(sizeof(struct WPaintData), "WPaintData"); 01314 paint_stroke_set_mode_data(stroke, wpd); 01315 view3d_set_viewcontext(C, &wpd->vc); 01316 wpd->vgroup_mirror= -1; 01317 01318 /*set up auto-normalize, and generate map for detecting which 01319 vgroups affect deform bones*/ 01320 wpd->auto_normalize = ts->auto_normalize; 01321 if (wpd->auto_normalize) 01322 wpd->vgroup_validmap = wpaint_make_validmap(ob); 01323 01324 // if(qual & LR_CTRLKEY) { 01325 // sample_wpaint(scene, ar, v3d, 0); 01326 // return; 01327 // } 01328 // if(qual & LR_SHIFTKEY) { 01329 // sample_wpaint(scene, ar, v3d, 1); 01330 // return; 01331 // } 01332 01333 /* ALLOCATIONS! no return after this line */ 01334 /* painting on subsurfs should give correct points too, this returns me->totvert amount */ 01335 wpd->vertexcosnos= mesh_get_mapped_verts_nors(scene, ob); 01336 wpd->indexar= get_indexarray(me); 01337 copy_wpaint_prev(wp, me->dvert, me->totvert); 01338 01339 /* this happens on a Bone select, when no vgroup existed yet */ 01340 if(ob->actdef<=0) { 01341 Object *modob; 01342 if((modob = modifiers_isDeformedByArmature(ob))) { 01343 Bone *actbone= ((bArmature *)modob->data)->act_bone; 01344 if(actbone) { 01345 bPoseChannel *pchan= get_pose_channel(modob->pose, actbone->name); 01346 01347 if(pchan) { 01348 bDeformGroup *dg= defgroup_find_name(ob, pchan->name); 01349 if(dg==NULL) 01350 dg= ED_vgroup_add_name(ob, pchan->name); /* sets actdef */ 01351 else 01352 ob->actdef= 1 + defgroup_find_index(ob, dg); 01353 } 01354 } 01355 } 01356 } 01357 if(ob->defbase.first==NULL) { 01358 ED_vgroup_add(ob); 01359 } 01360 01361 // if(ob->lay & v3d->lay); else error("Active object is not in this layer"); 01362 01363 /* imat for normals */ 01364 mul_m4_m4m4(mat, ob->obmat, wpd->vc.rv3d->viewmat); 01365 invert_m4_m4(imat, mat); 01366 copy_m3_m4(wpd->wpimat, imat); 01367 01368 /* if mirror painting, find the other group */ 01369 if(me->editflag & ME_EDIT_MIRROR_X) { 01370 wpaint_mirror_vgroup_ensure(ob, &wpd->vgroup_mirror); 01371 } 01372 01373 return 1; 01374 } 01375 01376 static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) 01377 { 01378 ToolSettings *ts= CTX_data_tool_settings(C); 01379 VPaint *wp= ts->wpaint; 01380 Brush *brush = paint_brush(&wp->paint); 01381 struct WPaintData *wpd= paint_stroke_mode_data(stroke); 01382 ViewContext *vc; 01383 Object *ob; 01384 Mesh *me; 01385 float mat[4][4]; 01386 float paintweight; 01387 int *indexar; 01388 int totindex, index, totw, flip; 01389 float alpha; 01390 float mval[2], pressure; 01391 01392 /* cannot paint if there is no stroke data */ 01393 if (wpd == NULL) { 01394 // XXX: force a redraw here, since even though we can't paint, 01395 // at least view won't freeze until stroke ends 01396 ED_region_tag_redraw(CTX_wm_region(C)); 01397 return; 01398 } 01399 01400 vc= &wpd->vc; 01401 ob= vc->obact; 01402 me= ob->data; 01403 indexar= wpd->indexar; 01404 01405 view3d_operator_needs_opengl(C); 01406 01407 /* load projection matrix */ 01408 mul_m4_m4m4(mat, ob->obmat, vc->rv3d->persmat); 01409 01410 flip = RNA_boolean_get(itemptr, "pen_flip"); 01411 pressure = RNA_float_get(itemptr, "pressure"); 01412 RNA_float_get_array(itemptr, "mouse", mval); 01413 mval[0]-= vc->ar->winrct.xmin; 01414 mval[1]-= vc->ar->winrct.ymin; 01415 01416 swap_m4m4(wpd->vc.rv3d->persmat, mat); 01417 01418 /* which faces are involved */ 01419 if(wp->flag & VP_AREA) { 01420 totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush_size(brush)); 01421 } 01422 else { 01423 indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]); 01424 if(indexar[0]) totindex= 1; 01425 else totindex= 0; 01426 } 01427 01428 if(wp->flag & VP_COLINDEX) { 01429 for(index=0; index<totindex; index++) { 01430 if(indexar[index] && indexar[index]<=me->totface) { 01431 MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); 01432 01433 if(mface->mat_nr!=ob->actcol-1) { 01434 indexar[index]= 0; 01435 } 01436 } 01437 } 01438 } 01439 01440 if((me->editflag & ME_EDIT_PAINT_MASK) && me->mface) { 01441 for(index=0; index<totindex; index++) { 01442 if(indexar[index] && indexar[index]<=me->totface) { 01443 MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); 01444 01445 if((mface->flag & ME_FACE_SEL)==0) { 01446 indexar[index]= 0; 01447 } 01448 } 01449 } 01450 } 01451 01452 /* make sure each vertex gets treated only once */ 01453 /* and calculate filter weight */ 01454 totw= 0; 01455 if(brush->vertexpaint_tool==VP_BLUR) 01456 paintweight= 0.0f; 01457 else 01458 paintweight= ts->vgroup_weight; 01459 01460 for(index=0; index<totindex; index++) { 01461 if(indexar[index] && indexar[index]<=me->totface) { 01462 MFace *mface= me->mface + (indexar[index]-1); 01463 01464 (me->dvert+mface->v1)->flag= 1; 01465 (me->dvert+mface->v2)->flag= 1; 01466 (me->dvert+mface->v3)->flag= 1; 01467 if(mface->v4) (me->dvert+mface->v4)->flag= 1; 01468 01469 if(brush->vertexpaint_tool==VP_BLUR) { 01470 MDeformWeight *dw, *(*dw_func)(MDeformVert *, const int); 01471 01472 if(wp->flag & VP_ONLYVGROUP) 01473 dw_func= (MDeformWeight *(*)(MDeformVert *, const int))defvert_find_index; 01474 else 01475 dw_func= defvert_verify_index; 01476 01477 dw= dw_func(me->dvert+mface->v1, ob->actdef-1); 01478 if(dw) {paintweight+= dw->weight; totw++;} 01479 dw= dw_func(me->dvert+mface->v2, ob->actdef-1); 01480 if(dw) {paintweight+= dw->weight; totw++;} 01481 dw= dw_func(me->dvert+mface->v3, ob->actdef-1); 01482 if(dw) {paintweight+= dw->weight; totw++;} 01483 if(mface->v4) { 01484 dw= dw_func(me->dvert+mface->v4, ob->actdef-1); 01485 if(dw) {paintweight+= dw->weight; totw++;} 01486 } 01487 } 01488 } 01489 } 01490 01491 if(brush->vertexpaint_tool==VP_BLUR) 01492 paintweight/= (float)totw; 01493 01494 for(index=0; index<totindex; index++) { 01495 01496 if(indexar[index] && indexar[index]<=me->totface) { 01497 MFace *mface= me->mface + (indexar[index]-1); 01498 01499 if((me->dvert+mface->v1)->flag) { 01500 alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v1, mval, pressure); 01501 if(alpha) { 01502 do_weight_paint_vertex(wp, ob, mface->v1, 01503 alpha, paintweight, flip, wpd->vgroup_mirror, 01504 wpd->vgroup_validmap); 01505 } 01506 (me->dvert+mface->v1)->flag= 0; 01507 } 01508 01509 if((me->dvert+mface->v2)->flag) { 01510 alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v2, mval, pressure); 01511 if(alpha) { 01512 do_weight_paint_vertex(wp, ob, mface->v2, 01513 alpha, paintweight, flip, wpd->vgroup_mirror, 01514 wpd->vgroup_validmap); 01515 } 01516 (me->dvert+mface->v2)->flag= 0; 01517 } 01518 01519 if((me->dvert+mface->v3)->flag) { 01520 alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v3, mval, pressure); 01521 if(alpha) { 01522 do_weight_paint_vertex(wp, ob, mface->v3, 01523 alpha, paintweight, flip, wpd->vgroup_mirror, 01524 wpd->vgroup_validmap); 01525 } 01526 (me->dvert+mface->v3)->flag= 0; 01527 } 01528 01529 if((me->dvert+mface->v4)->flag) { 01530 if(mface->v4) { 01531 alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v4, mval, pressure); 01532 if(alpha) { 01533 do_weight_paint_vertex(wp, ob, mface->v4, 01534 alpha, paintweight, flip, wpd->vgroup_mirror, 01535 wpd->vgroup_validmap); 01536 } 01537 (me->dvert+mface->v4)->flag= 0; 01538 } 01539 } 01540 } 01541 } 01542 01543 swap_m4m4(vc->rv3d->persmat, mat); 01544 01545 DAG_id_tag_update(ob->data, 0); 01546 ED_region_tag_redraw(vc->ar); 01547 } 01548 01549 static void wpaint_stroke_done(bContext *C, struct PaintStroke *stroke) 01550 { 01551 ToolSettings *ts= CTX_data_tool_settings(C); 01552 Object *ob= CTX_data_active_object(C); 01553 struct WPaintData *wpd= paint_stroke_mode_data(stroke); 01554 01555 if(wpd) { 01556 if(wpd->vertexcosnos) 01557 MEM_freeN(wpd->vertexcosnos); 01558 MEM_freeN(wpd->indexar); 01559 01560 if (wpd->vgroup_validmap) 01561 MEM_freeN(wpd->vgroup_validmap); 01562 01563 MEM_freeN(wpd); 01564 } 01565 01566 /* frees prev buffer */ 01567 copy_wpaint_prev(ts->wpaint, NULL, 0); 01568 01569 /* and particles too */ 01570 if(ob->particlesystem.first) { 01571 ParticleSystem *psys; 01572 int i; 01573 01574 for(psys= ob->particlesystem.first; psys; psys= psys->next) { 01575 for(i=0; i<PSYS_TOT_VG; i++) { 01576 if(psys->vgroup[i]==ob->actdef) { 01577 psys->recalc |= PSYS_RECALC_RESET; 01578 break; 01579 } 01580 } 01581 } 01582 } 01583 01584 DAG_id_tag_update(ob->data, 0); 01585 } 01586 01587 01588 static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) 01589 { 01590 01591 op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start, 01592 wpaint_stroke_update_step, 01593 wpaint_stroke_done, event->type); 01594 01595 /* add modal handler */ 01596 WM_event_add_modal_handler(C, op); 01597 01598 op->type->modal(C, op, event); 01599 01600 return OPERATOR_RUNNING_MODAL; 01601 } 01602 01603 static int wpaint_cancel(bContext *C, wmOperator *op) 01604 { 01605 paint_stroke_cancel(C, op); 01606 01607 return OPERATOR_CANCELLED; 01608 } 01609 01610 void PAINT_OT_weight_paint(wmOperatorType *ot) 01611 { 01612 01613 /* identifiers */ 01614 ot->name= "Weight Paint"; 01615 ot->idname= "PAINT_OT_weight_paint"; 01616 01617 /* api callbacks */ 01618 ot->invoke= wpaint_invoke; 01619 ot->modal= paint_stroke_modal; 01620 /* ot->exec= vpaint_exec; <-- needs stroke property */ 01621 ot->poll= weight_paint_poll; 01622 ot->cancel= wpaint_cancel; 01623 01624 /* flags */ 01625 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; 01626 01627 RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); 01628 } 01629 01630 static int weight_paint_set_exec(bContext *C, wmOperator *UNUSED(op)) 01631 { 01632 struct Scene *scene= CTX_data_scene(C); 01633 Object *obact = CTX_data_active_object(C); 01634 01635 wpaint_fill(scene->toolsettings->wpaint, obact, scene->toolsettings->vgroup_weight); 01636 ED_region_tag_redraw(CTX_wm_region(C)); // XXX - should redraw all 3D views 01637 return OPERATOR_FINISHED; 01638 } 01639 01640 void PAINT_OT_weight_set(wmOperatorType *ot) 01641 { 01642 /* identifiers */ 01643 ot->name= "Set Weight"; 01644 ot->idname= "PAINT_OT_weight_set"; 01645 01646 /* api callbacks */ 01647 ot->exec= weight_paint_set_exec; 01648 ot->poll= facemask_paint_poll; 01649 01650 /* flags */ 01651 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01652 } 01653 01654 /* ************ set / clear vertex paint mode ********** */ 01655 01656 01657 static int set_vpaint(bContext *C, wmOperator *op) /* toggle */ 01658 { 01659 Object *ob= CTX_data_active_object(C); 01660 Scene *scene= CTX_data_scene(C); 01661 VPaint *vp= scene->toolsettings->vpaint; 01662 Mesh *me; 01663 01664 me= get_mesh(ob); 01665 01666 if(me==NULL || object_data_is_libdata(ob)) { 01667 ob->mode &= ~OB_MODE_VERTEX_PAINT; 01668 return OPERATOR_PASS_THROUGH; 01669 } 01670 01671 if(me && me->mcol==NULL) make_vertexcol(ob); 01672 01673 /* toggle: end vpaint */ 01674 if(ob->mode & OB_MODE_VERTEX_PAINT) { 01675 01676 ob->mode &= ~OB_MODE_VERTEX_PAINT; 01677 } 01678 else { 01679 ob->mode |= OB_MODE_VERTEX_PAINT; 01680 /* Turn off weight painting */ 01681 if (ob->mode & OB_MODE_WEIGHT_PAINT) 01682 set_wpaint(C, op); 01683 01684 if(vp==NULL) 01685 vp= scene->toolsettings->vpaint= new_vpaint(0); 01686 01687 paint_cursor_start(C, vertex_paint_poll); 01688 01689 paint_init(&vp->paint, PAINT_CURSOR_VERTEX_PAINT); 01690 } 01691 01692 if (me) 01693 /* update modifier stack for mapping requirements */ 01694 DAG_id_tag_update(&me->id, 0); 01695 01696 WM_event_add_notifier(C, NC_SCENE|ND_MODE, scene); 01697 01698 return OPERATOR_FINISHED; 01699 } 01700 01701 void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot) 01702 { 01703 01704 /* identifiers */ 01705 ot->name= "Vertex Paint Mode"; 01706 ot->idname= "PAINT_OT_vertex_paint_toggle"; 01707 01708 /* api callbacks */ 01709 ot->exec= set_vpaint; 01710 ot->poll= paint_poll_test; 01711 01712 /* flags */ 01713 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01714 } 01715 01716 01717 01718 /* ********************** vertex paint operator ******************* */ 01719 01720 /* Implementation notes: 01721 01722 Operator->invoke() 01723 - validate context (add mcol) 01724 - create customdata storage 01725 - call paint once (mouse click) 01726 - add modal handler 01727 01728 Operator->modal() 01729 - for every mousemove, apply vertex paint 01730 - exit on mouse release, free customdata 01731 (return OPERATOR_FINISHED also removes handler and operator) 01732 01733 For future: 01734 - implement a stroke event (or mousemove with past positons) 01735 - revise whether op->customdata should be added in object, in set_vpaint 01736 01737 */ 01738 01739 typedef struct VPaintData { 01740 ViewContext vc; 01741 unsigned int paintcol; 01742 int *indexar; 01743 float *vertexcosnos; 01744 float vpimat[3][3]; 01745 } VPaintData; 01746 01747 static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *UNUSED(event)) 01748 { 01749 ToolSettings *ts= CTX_data_tool_settings(C); 01750 struct PaintStroke *stroke = op->customdata; 01751 VPaint *vp= ts->vpaint; 01752 struct VPaintData *vpd; 01753 Object *ob= CTX_data_active_object(C); 01754 Mesh *me; 01755 float mat[4][4], imat[4][4]; 01756 01757 /* context checks could be a poll() */ 01758 me= get_mesh(ob); 01759 if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH; 01760 01761 if(me->mcol==NULL) make_vertexcol(ob); 01762 if(me->mcol==NULL) return OPERATOR_CANCELLED; 01763 01764 /* make mode data storage */ 01765 vpd= MEM_callocN(sizeof(struct VPaintData), "VPaintData"); 01766 paint_stroke_set_mode_data(stroke, vpd); 01767 view3d_set_viewcontext(C, &vpd->vc); 01768 01769 vpd->vertexcosnos= mesh_get_mapped_verts_nors(vpd->vc.scene, ob); 01770 vpd->indexar= get_indexarray(me); 01771 vpd->paintcol= vpaint_get_current_col(vp); 01772 01773 /* for filtering */ 01774 copy_vpaint_prev(vp, (unsigned int *)me->mcol, me->totface); 01775 01776 /* some old cruft to sort out later */ 01777 mul_m4_m4m4(mat, ob->obmat, vpd->vc.rv3d->viewmat); 01778 invert_m4_m4(imat, mat); 01779 copy_m3_m4(vpd->vpimat, imat); 01780 01781 return 1; 01782 } 01783 01784 static void vpaint_paint_face(VPaint *vp, VPaintData *vpd, Object *ob, int index, const float mval[2], float pressure, int UNUSED(flip)) 01785 { 01786 ViewContext *vc = &vpd->vc; 01787 Brush *brush = paint_brush(&vp->paint); 01788 Mesh *me = get_mesh(ob); 01789 MFace *mface= ((MFace*)me->mface) + index; 01790 unsigned int *mcol= ((unsigned int*)me->mcol) + 4*index; 01791 unsigned int *mcolorig= ((unsigned int*)vp->vpaint_prev) + 4*index; 01792 float alpha; 01793 int i; 01794 01795 if((vp->flag & VP_COLINDEX && mface->mat_nr!=ob->actcol-1) || 01796 ((me->editflag & ME_EDIT_PAINT_MASK) && !(mface->flag & ME_FACE_SEL))) 01797 return; 01798 01799 if(brush->vertexpaint_tool==VP_BLUR) { 01800 unsigned int fcol1= mcol_blend( mcol[0], mcol[1], 128); 01801 if(mface->v4) { 01802 unsigned int fcol2= mcol_blend( mcol[2], mcol[3], 128); 01803 vpd->paintcol= mcol_blend( fcol1, fcol2, 128); 01804 } 01805 else { 01806 vpd->paintcol= mcol_blend( mcol[2], fcol1, 170); 01807 } 01808 01809 } 01810 01811 for(i = 0; i < (mface->v4 ? 4 : 3); ++i) { 01812 alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*(&mface->v1)[i], mval, pressure); 01813 if(alpha) 01814 vpaint_blend(vp, mcol+i, mcolorig+i, vpd->paintcol, (int)(alpha*255.0f)); 01815 } 01816 } 01817 01818 static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) 01819 { 01820 ToolSettings *ts= CTX_data_tool_settings(C); 01821 struct VPaintData *vpd = paint_stroke_mode_data(stroke); 01822 VPaint *vp= ts->vpaint; 01823 Brush *brush = paint_brush(&vp->paint); 01824 ViewContext *vc= &vpd->vc; 01825 Object *ob= vc->obact; 01826 Mesh *me= ob->data; 01827 float mat[4][4]; 01828 int *indexar= vpd->indexar; 01829 int totindex, index, flip; 01830 float pressure, mval[2]; 01831 01832 RNA_float_get_array(itemptr, "mouse", mval); 01833 flip = RNA_boolean_get(itemptr, "pen_flip"); 01834 pressure = RNA_float_get(itemptr, "pressure"); 01835 01836 view3d_operator_needs_opengl(C); 01837 01838 /* load projection matrix */ 01839 mul_m4_m4m4(mat, ob->obmat, vc->rv3d->persmat); 01840 01841 mval[0]-= vc->ar->winrct.xmin; 01842 mval[1]-= vc->ar->winrct.ymin; 01843 01844 01845 /* which faces are involved */ 01846 if(vp->flag & VP_AREA) { 01847 totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush_size(brush)); 01848 } 01849 else { 01850 indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]); 01851 if(indexar[0]) totindex= 1; 01852 else totindex= 0; 01853 } 01854 01855 swap_m4m4(vc->rv3d->persmat, mat); 01856 01857 for(index=0; index<totindex; index++) { 01858 if(indexar[index] && indexar[index]<=me->totface) 01859 vpaint_paint_face(vp, vpd, ob, indexar[index]-1, mval, pressure, flip); 01860 } 01861 01862 swap_m4m4(vc->rv3d->persmat, mat); 01863 01864 /* was disabled because it is slow, but necessary for blur */ 01865 if(brush->vertexpaint_tool == VP_BLUR) 01866 do_shared_vertexcol(me); 01867 01868 ED_region_tag_redraw(vc->ar); 01869 01870 DAG_id_tag_update(ob->data, 0); 01871 } 01872 01873 static void vpaint_stroke_done(bContext *C, struct PaintStroke *stroke) 01874 { 01875 ToolSettings *ts= CTX_data_tool_settings(C); 01876 struct VPaintData *vpd= paint_stroke_mode_data(stroke); 01877 01878 if(vpd->vertexcosnos) 01879 MEM_freeN(vpd->vertexcosnos); 01880 MEM_freeN(vpd->indexar); 01881 01882 /* frees prev buffer */ 01883 copy_vpaint_prev(ts->vpaint, NULL, 0); 01884 01885 MEM_freeN(vpd); 01886 } 01887 01888 static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) 01889 { 01890 01891 op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start, 01892 vpaint_stroke_update_step, 01893 vpaint_stroke_done, event->type); 01894 01895 /* add modal handler */ 01896 WM_event_add_modal_handler(C, op); 01897 01898 op->type->modal(C, op, event); 01899 01900 return OPERATOR_RUNNING_MODAL; 01901 } 01902 01903 static int vpaint_cancel(bContext *C, wmOperator *op) 01904 { 01905 paint_stroke_cancel(C, op); 01906 01907 return OPERATOR_CANCELLED; 01908 } 01909 01910 void PAINT_OT_vertex_paint(wmOperatorType *ot) 01911 { 01912 /* identifiers */ 01913 ot->name= "Vertex Paint"; 01914 ot->idname= "PAINT_OT_vertex_paint"; 01915 01916 /* api callbacks */ 01917 ot->invoke= vpaint_invoke; 01918 ot->modal= paint_stroke_modal; 01919 /* ot->exec= vpaint_exec; <-- needs stroke property */ 01920 ot->poll= vertex_paint_poll; 01921 ot->cancel= vpaint_cancel; 01922 01923 /* flags */ 01924 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; 01925 01926 RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); 01927 } 01928 01929 /* ********************** weight from bones operator ******************* */ 01930 01931 static int weight_from_bones_poll(bContext *C) 01932 { 01933 Object *ob= CTX_data_active_object(C); 01934 01935 return (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && modifiers_isDeformedByArmature(ob)); 01936 } 01937 01938 static int weight_from_bones_exec(bContext *C, wmOperator *op) 01939 { 01940 Scene *scene= CTX_data_scene(C); 01941 Object *ob= CTX_data_active_object(C); 01942 Object *armob= modifiers_isDeformedByArmature(ob); 01943 Mesh *me= ob->data; 01944 int type= RNA_enum_get(op->ptr, "type"); 01945 01946 create_vgroups_from_armature(op->reports, scene, ob, armob, type, (me->editflag & ME_EDIT_MIRROR_X)); 01947 01948 DAG_id_tag_update(&me->id, 0); 01949 WM_event_add_notifier(C, NC_GEOM|ND_DATA, me); 01950 01951 return OPERATOR_FINISHED; 01952 } 01953 01954 void PAINT_OT_weight_from_bones(wmOperatorType *ot) 01955 { 01956 static EnumPropertyItem type_items[]= { 01957 {ARM_GROUPS_AUTO, "AUTOMATIC", 0, "Automatic", "Automatic weights froms bones"}, 01958 {ARM_GROUPS_ENVELOPE, "ENVELOPES", 0, "From Envelopes", "Weights from envelopes with user defined radius"}, 01959 {0, NULL, 0, NULL, NULL}}; 01960 01961 /* identifiers */ 01962 ot->name= "Weight from Bones"; 01963 ot->idname= "PAINT_OT_weight_from_bones"; 01964 01965 /* api callbacks */ 01966 ot->exec= weight_from_bones_exec; 01967 ot->invoke= WM_menu_invoke; 01968 ot->poll= weight_from_bones_poll; 01969 01970 /* flags */ 01971 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01972 01973 /* properties */ 01974 ot->prop= RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights."); 01975 } 01976