4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): none yet.
27 * ***** END GPL LICENSE BLOCK *****
30 /** \file blender/editors/sculpt_paint/paint_vertex.c
44 #include "MEM_guardedalloc.h"
46 #include "BLI_blenlib.h"
48 #include "BLI_utildefines.h"
49 #include "BLI_ghash.h"
51 #include "IMB_imbuf.h"
52 #include "IMB_imbuf_types.h"
54 #include "DNA_armature_types.h"
55 #include "DNA_mesh_types.h"
56 #include "DNA_particle_types.h"
57 #include "DNA_scene_types.h"
58 #include "DNA_brush_types.h"
59 #include "DNA_object_types.h"
60 #include "DNA_meshdata_types.h"
62 #include "RNA_access.h"
63 #include "RNA_define.h"
64 #include "RNA_enum_types.h"
66 #include "BKE_DerivedMesh.h"
67 #include "BKE_armature.h"
68 #include "BKE_action.h"
69 #include "BKE_brush.h"
70 #include "BKE_context.h"
71 #include "BKE_depsgraph.h"
72 #include "BKE_deform.h"
74 #include "BKE_modifier.h"
75 #include "BKE_object.h"
76 #include "BKE_paint.h"
77 #include "BKE_report.h"
83 #include "ED_armature.h"
85 #include "ED_screen.h"
86 #include "ED_view3d.h"
88 #include "paint_intern.h"
90 /* brush->vertexpaint_tool */
99 /* polling - retrieve whether cursor should be set or operator should be done */
102 /* Returns true if vertex paint mode is active */
103 int vertex_paint_mode_poll(bContext *C)
105 Object *ob = CTX_data_active_object(C);
107 return ob && ob->mode == OB_MODE_VERTEX_PAINT && ((Mesh *)ob->data)->totface;
110 int vertex_paint_poll(bContext *C)
112 if(vertex_paint_mode_poll(C) &&
113 paint_brush(&CTX_data_tool_settings(C)->vpaint->paint)) {
114 ScrArea *sa= CTX_wm_area(C);
115 if(sa->spacetype==SPACE_VIEW3D) {
116 ARegion *ar= CTX_wm_region(C);
117 if(ar->regiontype==RGN_TYPE_WINDOW)
124 int weight_paint_mode_poll(bContext *C)
126 Object *ob = CTX_data_active_object(C);
128 return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((Mesh *)ob->data)->totface;
131 int weight_paint_poll(bContext *C)
133 Object *ob= CTX_data_active_object(C);
137 (ob->mode & OB_MODE_WEIGHT_PAINT) &&
138 (paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != NULL) &&
139 (sa= CTX_wm_area(C)) &&
140 (sa->spacetype == SPACE_VIEW3D)
142 ARegion *ar= CTX_wm_region(C);
143 if(ar->regiontype==RGN_TYPE_WINDOW) {
150 static VPaint *new_vpaint(int wpaint)
152 VPaint *vp= MEM_callocN(sizeof(VPaint), "VPaint");
154 vp->flag= VP_AREA+VP_SPRAY;
162 static int *get_indexarray(Mesh *me)
164 return MEM_mallocN(sizeof(int)*(me->totface+1), "vertexpaint");
168 /* in contradiction to cpack drawing colors, the MCOL colors (vpaint colors) are per byte!
169 so not endian sensitive. Mcol = ABGR!!! so be cautious with cpack calls */
171 static unsigned int rgba_to_mcol(float r, float g, float b, float a)
177 ir= floor(255.0f * r);
178 if(ir<0) ir= 0; else if(ir>255) ir= 255;
179 ig= floor(255.0f * g);
180 if(ig<0) ig= 0; else if(ig>255) ig= 255;
181 ib= floor(255.0f * b);
182 if(ib<0) ib= 0; else if(ib>255) ib= 255;
183 ia= floor(255.0f * a);
184 if(ia<0) ia= 0; else if(ia>255) ia= 255;
196 unsigned int vpaint_get_current_col(VPaint *vp)
198 Brush *brush = paint_brush(&vp->paint);
199 return rgba_to_mcol(brush->rgb[0], brush->rgb[1], brush->rgb[2], 1.0f);
202 static void do_shared_vertexcol(Mesh *me)
204 /* if no mcol: do not do */
205 /* if tface: only the involved faces, otherwise all */
209 short *scolmain, *scol;
212 if(me->mcol==NULL || me->totvert==0 || me->totface==0) return;
214 scolmain= MEM_callocN(4*sizeof(short)*me->totvert, "colmain");
218 mcol= (char *)me->mcol;
219 for(a=me->totface; a>0; a--, mface++, mcol+=16) {
220 if((tface && tface->mode & TF_SHAREDCOL) || (me->editflag & ME_EDIT_PAINT_MASK)==0) {
221 scol= scolmain+4*mface->v1;
222 scol[0]++; scol[1]+= mcol[1]; scol[2]+= mcol[2]; scol[3]+= mcol[3];
223 scol= scolmain+4*mface->v2;
224 scol[0]++; scol[1]+= mcol[5]; scol[2]+= mcol[6]; scol[3]+= mcol[7];
225 scol= scolmain+4*mface->v3;
226 scol[0]++; scol[1]+= mcol[9]; scol[2]+= mcol[10]; scol[3]+= mcol[11];
228 scol= scolmain+4*mface->v4;
229 scol[0]++; scol[1]+= mcol[13]; scol[2]+= mcol[14]; scol[3]+= mcol[15];
248 mcol= (char *)me->mcol;
249 for(a=me->totface; a>0; a--, mface++, mcol+=16) {
250 if((tface && tface->mode & TF_SHAREDCOL) || (me->editflag & ME_EDIT_PAINT_MASK)==0) {
251 scol= scolmain+4*mface->v1;
252 mcol[1]= scol[1]; mcol[2]= scol[2]; mcol[3]= scol[3];
253 scol= scolmain+4*mface->v2;
254 mcol[5]= scol[1]; mcol[6]= scol[2]; mcol[7]= scol[3];
255 scol= scolmain+4*mface->v3;
256 mcol[9]= scol[1]; mcol[10]= scol[2]; mcol[11]= scol[3];
258 scol= scolmain+4*mface->v4;
259 mcol[13]= scol[1]; mcol[14]= scol[2]; mcol[15]= scol[3];
268 static void make_vertexcol(Object *ob) /* single ob */
271 if(!ob || ob->id.lib) return;
274 if(me->edit_mesh) return;
276 /* copies from shadedisplist to mcol */
278 CustomData_add_layer(&me->fdata, CD_MCOL, CD_CALLOC, NULL, me->totface);
279 mesh_update_customdata_pointers(me);
283 // shadeMeshMCol(scene, ob, me);
286 memset(me->mcol, 255, 4*sizeof(MCol)*me->totface);
288 DAG_id_tag_update(&me->id, 0);
292 /* mirror_vgroup is set to -1 when invalid */
293 static void wpaint_mirror_vgroup_ensure(Object *ob, int *vgroup_mirror)
295 bDeformGroup *defgroup= BLI_findlink(&ob->defbase, ob->actdef - 1);
298 bDeformGroup *curdef;
300 char name[MAXBONENAME];
302 flip_side_name(name, defgroup->name, FALSE);
304 if(strcmp(name, defgroup->name) != 0) {
305 for (curdef= ob->defbase.first, mirrdef= 0; curdef; curdef=curdef->next, mirrdef++) {
306 if (!strcmp(curdef->name, name)) {
312 int olddef= ob->actdef; /* tsk, ED_vgroup_add sets the active defgroup */
313 curdef= ED_vgroup_add_name(ob, name);
317 /* curdef should never be NULL unless this is
318 * a lamp and ED_vgroup_add_name fails */
320 *vgroup_mirror= mirrdef;
329 static void copy_vpaint_prev(VPaint *vp, unsigned int *mcol, int tot)
331 if(vp->vpaint_prev) {
332 MEM_freeN(vp->vpaint_prev);
333 vp->vpaint_prev= NULL;
337 if(mcol==NULL || tot==0) return;
339 vp->vpaint_prev= MEM_mallocN(4*sizeof(int)*tot, "vpaint_prev");
340 memcpy(vp->vpaint_prev, mcol, 4*sizeof(int)*tot);
344 static void copy_wpaint_prev (VPaint *wp, MDeformVert *dverts, int dcount)
346 if (wp->wpaint_prev) {
347 free_dverts(wp->wpaint_prev, wp->tot);
348 wp->wpaint_prev= NULL;
351 if(dverts && dcount) {
353 wp->wpaint_prev = MEM_mallocN (sizeof(MDeformVert)*dcount, "wpaint prev");
355 copy_dverts (wp->wpaint_prev, dverts, dcount);
360 void vpaint_fill(Object *ob, unsigned int paintcol)
368 if(me==NULL || me->totface==0) return;
373 selected= (me->editflag & ME_EDIT_PAINT_MASK);
376 mcol = (unsigned int*)me->mcol;
377 for (i = 0; i < me->totface; i++, mf++, mcol+=4) {
378 if (!selected || mf->flag & ME_FACE_SEL) {
386 DAG_id_tag_update(&me->id, 0);
390 /* fills in the selected faces with the current weight and vertex group */
391 void wpaint_fill(VPaint *wp, Object *ob, float paintweight)
395 MDeformWeight *dw, *uw;
398 unsigned int faceverts[5]={0,0,0,0,0};
400 int vgroup_mirror= -1;
406 if(me==NULL || me->totface==0 || me->dvert==NULL || !me->mface) return;
408 selected= (me->editflag & ME_EDIT_PAINT_MASK);
410 use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
412 indexar= get_indexarray(me);
415 for(index=0, mface=me->mface; index<me->totface; index++, mface++) {
416 if((mface->flag & ME_FACE_SEL)==0)
419 indexar[index]= index+1;
423 for(index=0; index<me->totface; index++)
424 indexar[index]= index+1;
427 vgroup= ob->actdef-1;
429 /* if mirror painting, find the other group */
430 if(me->editflag & ME_EDIT_MIRROR_X) {
431 wpaint_mirror_vgroup_ensure(ob, &vgroup_mirror);
434 copy_wpaint_prev(wp, me->dvert, me->totvert);
436 for(index=0; index<me->totface; index++) {
437 if(indexar[index] && indexar[index]<=me->totface) {
438 mface= me->mface + (indexar[index]-1);
439 /* just so we can loop through the verts */
440 faceverts[0]= mface->v1;
441 faceverts[1]= mface->v2;
442 faceverts[2]= mface->v3;
443 faceverts[3]= mface->v4;
444 for (i=0; i<3 || faceverts[i]; i++) {
445 if(!me->dvert[faceverts[i]].flag) {
447 if(use_vert_sel && !(me->mvert[faceverts[i]].flag & SELECT)) {
451 dw= defvert_verify_index(me->dvert+faceverts[i], vgroup);
453 uw= defvert_verify_index(wp->wpaint_prev+faceverts[i], vgroup);
454 uw->weight= dw->weight; /* set the undo weight */
455 dw->weight= paintweight;
457 if(me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */
458 int j= mesh_get_x_mirror_vert(ob, faceverts[i]);
460 /* copy, not paint again */
461 if(vgroup_mirror != -1) {
462 dw= defvert_verify_index(me->dvert+j, vgroup_mirror);
463 uw= defvert_verify_index(wp->wpaint_prev+j, vgroup_mirror);
465 dw= defvert_verify_index(me->dvert+j, vgroup);
466 uw= defvert_verify_index(wp->wpaint_prev+j, vgroup);
468 uw->weight= dw->weight; /* set the undo weight */
469 dw->weight= paintweight;
473 (me->dvert+faceverts[i])->flag= 1;
480 while (index<me->totvert) {
481 (me->dvert+index)->flag= 0;
486 copy_wpaint_prev(wp, NULL, 0);
488 DAG_id_tag_update(&me->id, 0);
491 /* XXX: should be re-implemented as a vertex/weight paint 'color correct' operator
493 void vpaint_dogamma(Scene *scene)
495 VPaint *vp= scene->toolsettings->vpaint;
500 unsigned char *cp, gamtab[256];
505 if(!(ob->mode & OB_MODE_VERTEX_PAINT)) return;
506 if(me==0 || me->mcol==0 || me->totface==0) return;
509 for(a=0; a<256; a++) {
511 fac= ((float)a)/255.0;
512 fac= vp->mul*pow( fac, igam);
516 if(temp<=0) gamtab[a]= 0;
517 else if(temp>=255) gamtab[a]= 255;
518 else gamtab[a]= temp;
522 cp= (unsigned char *)me->mcol;
525 cp[1]= gamtab[ cp[1] ];
526 cp[2]= gamtab[ cp[2] ];
527 cp[3]= gamtab[ cp[3] ];
534 static unsigned int mcol_blend(unsigned int col1, unsigned int col2, int fac)
536 char *cp1, *cp2, *cp;
540 if(fac==0) return col1;
541 if(fac>=255) return col2;
550 cp[1]= (mfac*cp1[1]+fac*cp2[1])/255;
551 cp[2]= (mfac*cp1[2]+fac*cp2[2])/255;
552 cp[3]= (mfac*cp1[3]+fac*cp2[3])/255;
557 static unsigned int mcol_add(unsigned int col1, unsigned int col2, int fac)
559 char *cp1, *cp2, *cp;
563 if(fac==0) return col1;
570 temp= cp1[1] + ((fac*cp2[1])/255);
571 if(temp>254) cp[1]= 255; else cp[1]= temp;
572 temp= cp1[2] + ((fac*cp2[2])/255);
573 if(temp>254) cp[2]= 255; else cp[2]= temp;
574 temp= cp1[3] + ((fac*cp2[3])/255);
575 if(temp>254) cp[3]= 255; else cp[3]= temp;
580 static unsigned int mcol_sub(unsigned int col1, unsigned int col2, int fac)
582 char *cp1, *cp2, *cp;
586 if(fac==0) return col1;
593 temp= cp1[1] - ((fac*cp2[1])/255);
594 if(temp<0) cp[1]= 0; else cp[1]= temp;
595 temp= cp1[2] - ((fac*cp2[2])/255);
596 if(temp<0) cp[2]= 0; else cp[2]= temp;
597 temp= cp1[3] - ((fac*cp2[3])/255);
598 if(temp<0) cp[3]= 0; else cp[3]= temp;
603 static unsigned int mcol_mul(unsigned int col1, unsigned int col2, int fac)
605 char *cp1, *cp2, *cp;
609 if(fac==0) return col1;
617 /* first mul, then blend the fac */
619 cp[1]= (mfac*cp1[1] + fac*((cp2[1]*cp1[1])/255) )/255;
620 cp[2]= (mfac*cp1[2] + fac*((cp2[2]*cp1[2])/255) )/255;
621 cp[3]= (mfac*cp1[3] + fac*((cp2[3]*cp1[3])/255) )/255;
627 static unsigned int mcol_lighten(unsigned int col1, unsigned int col2, int fac)
629 char *cp1, *cp2, *cp;
633 if(fac==0) return col1;
634 if(fac>=255) return col2;
642 /* See if are lighter, if so mix, else dont do anything.
643 if the paint col is darker then the original, then ignore */
644 if (cp1[1]+cp1[2]+cp1[3] > cp2[1]+cp2[2]+cp2[3])
648 cp[1]= (mfac*cp1[1]+fac*cp2[1])/255;
649 cp[2]= (mfac*cp1[2]+fac*cp2[2])/255;
650 cp[3]= (mfac*cp1[3]+fac*cp2[3])/255;
655 static unsigned int mcol_darken(unsigned int col1, unsigned int col2, int fac)
657 char *cp1, *cp2, *cp;
661 if(fac==0) return col1;
662 if(fac>=255) return col2;
670 /* See if were darker, if so mix, else dont do anything.
671 if the paint col is brighter then the original, then ignore */
672 if (cp1[1]+cp1[2]+cp1[3] < cp2[1]+cp2[2]+cp2[3])
676 cp[1]= (mfac*cp1[1]+fac*cp2[1])/255;
677 cp[2]= (mfac*cp1[2]+fac*cp2[2])/255;
678 cp[3]= (mfac*cp1[3]+fac*cp2[3])/255;
682 static void vpaint_blend(VPaint *vp, unsigned int *col, unsigned int *colorig, unsigned int paintcol, int alpha)
684 Brush *brush = paint_brush(&vp->paint);
686 if(brush->vertexpaint_tool==VP_MIX || brush->vertexpaint_tool==VP_BLUR) *col= mcol_blend( *col, paintcol, alpha);
687 else if(brush->vertexpaint_tool==VP_ADD) *col= mcol_add( *col, paintcol, alpha);
688 else if(brush->vertexpaint_tool==VP_SUB) *col= mcol_sub( *col, paintcol, alpha);
689 else if(brush->vertexpaint_tool==VP_MUL) *col= mcol_mul( *col, paintcol, alpha);
690 else if(brush->vertexpaint_tool==VP_LIGHTEN) *col= mcol_lighten( *col, paintcol, alpha);
691 else if(brush->vertexpaint_tool==VP_DARKEN) *col= mcol_darken( *col, paintcol, alpha);
693 /* if no spray, clip color adding with colorig & orig alpha */
694 if((vp->flag & VP_SPRAY)==0) {
695 unsigned int testcol=0, a;
698 alpha= (int)(255.0f*brush_alpha(brush));
700 if(brush->vertexpaint_tool==VP_MIX || brush->vertexpaint_tool==VP_BLUR) testcol= mcol_blend( *colorig, paintcol, alpha);
701 else if(brush->vertexpaint_tool==VP_ADD) testcol= mcol_add( *colorig, paintcol, alpha);
702 else if(brush->vertexpaint_tool==VP_SUB) testcol= mcol_sub( *colorig, paintcol, alpha);
703 else if(brush->vertexpaint_tool==VP_MUL) testcol= mcol_mul( *colorig, paintcol, alpha);
704 else if(brush->vertexpaint_tool==VP_LIGHTEN) testcol= mcol_lighten( *colorig, paintcol, alpha);
705 else if(brush->vertexpaint_tool==VP_DARKEN) testcol= mcol_darken( *colorig, paintcol, alpha);
708 ct= (char *)&testcol;
713 if( cp[a]<ct[a] ) cp[a]= ct[a];
714 else if( cp[a]>co[a] ) cp[a]= co[a];
717 if( cp[a]<co[a] ) cp[a]= co[a];
718 else if( cp[a]>ct[a] ) cp[a]= ct[a];
725 static int sample_backbuf_area(ViewContext *vc, int *indexar, int totface, int x, int y, float size)
730 /* brecht: disabled this because it obviously failes for
731 brushes with size > 64, why is this here? */
732 /*if(size>64.0) size= 64.0;*/
734 ibuf= view3d_read_backbuf(vc, x-size, y-size, x+size, y+size);
736 unsigned int *rt= ibuf->rect;
738 memset(indexar, 0, sizeof(int)*(totface+1));
740 size= ibuf->x*ibuf->y;
744 index= WM_framebuffer_to_index(*rt);
745 if(index>0 && index<=totface)
752 for(a=1; a<=totface; a++) {
753 if(indexar[a]) indexar[tot++]= a;
762 static float calc_vp_alpha_dl(VPaint *vp, ViewContext *vc, float vpimat[][3], float *vert_nor, const float mval[2], float pressure)
764 Brush *brush = paint_brush(&vp->paint);
765 float fac, fac_2, size, dx, dy;
768 const int radius= brush_size(brush);
770 project_int_noclip(vc->ar, vert_nor, vertco);
771 dx= mval[0]-vertco[0];
772 dy= mval[1]-vertco[1];
774 if (brush_use_size_pressure(brush))
775 size = pressure * radius;
779 fac_2= dx*dx + dy*dy;
780 if(fac_2 > size*size) return 0.f;
783 alpha= brush_alpha(brush) * brush_curve_strength_clamp(brush, fac, size);
785 if (brush_use_alpha_pressure(brush))
788 if(vp->flag & VP_NORMALS) {
789 float *no= vert_nor+3;
792 fac= vpimat[2][0]*no[0]+vpimat[2][1]*no[1]+vpimat[2][2]*no[2];
794 dx= vpimat[0][0]*no[0]+vpimat[0][1]*no[1]+vpimat[0][2]*no[2];
795 dy= vpimat[1][0]*no[0]+vpimat[1][1]*no[1]+vpimat[1][2]*no[2];
797 alpha*= fac/sqrtf(dx*dx + dy*dy + fac*fac);
805 static void wpaint_blend(VPaint *wp, MDeformWeight *dw, MDeformWeight *uw, float alpha, float paintval, int flip, int multipaint)
807 Brush *brush = paint_brush(&wp->paint);
808 int tool = brush->vertexpaint_tool;
810 if(dw==NULL || uw==NULL) return;
815 paintval = 1.f - paintval; break;
821 tool= VP_DARKEN; break;
823 tool= VP_LIGHTEN; break;
827 if(tool==VP_MIX || tool==VP_BLUR)
828 dw->weight = paintval*alpha + dw->weight*(1.0f-alpha);
829 else if(tool==VP_ADD)
830 dw->weight += paintval*alpha;
831 else if(tool==VP_SUB)
832 dw->weight -= paintval*alpha;
833 else if(tool==VP_MUL)
834 /* first mul, then blend the fac */
835 dw->weight = ((1.0f-alpha) + alpha*paintval)*dw->weight;
836 else if(tool==VP_LIGHTEN) {
837 if (dw->weight < paintval)
838 dw->weight = paintval*alpha + dw->weight*(1.0f-alpha);
839 } else if(tool==VP_DARKEN) {
840 if (dw->weight > paintval)
841 dw->weight = paintval*alpha + dw->weight*(1.0f-alpha);
843 /* delay clamping until the end so multi-paint can function when the active group is at the limits */
844 if(multipaint == FALSE) {
845 CLAMP(dw->weight, 0.0f, 1.0f);
848 /* if no spray, clip result with orig weight & orig alpha */
849 if((wp->flag & VP_SPRAY)==0) {
852 alpha= brush_alpha(brush);
853 if(tool==VP_MIX || tool==VP_BLUR)
854 testw = paintval*alpha + uw->weight*(1.0f-alpha);
855 else if(tool==VP_ADD)
856 testw = uw->weight + paintval*alpha;
857 else if(tool==VP_SUB)
858 testw = uw->weight - paintval*alpha;
859 else if(tool==VP_MUL)
860 /* first mul, then blend the fac */
861 testw = ((1.0f-alpha) + alpha*paintval)*uw->weight;
862 else if(tool==VP_LIGHTEN) {
863 if (uw->weight < paintval)
864 testw = paintval*alpha + uw->weight*(1.0f-alpha);
867 } else if(tool==VP_DARKEN) {
868 if (uw->weight > paintval)
869 testw = paintval*alpha + uw->weight*(1.0f-alpha);
874 if(multipaint == FALSE) {
875 CLAMP(testw, 0.0f, 1.0f);
876 if( testw<uw->weight ) {
877 if(dw->weight < testw) dw->weight= testw;
878 else if(dw->weight > uw->weight) dw->weight= uw->weight;
881 if(dw->weight > testw) dw->weight= testw;
882 else if(dw->weight < uw->weight) dw->weight= uw->weight;
889 /* ----------------------------------------------------- */
892 /* sets wp->weight to the closest weight value to vertex */
893 /* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */
894 static int weight_sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
900 view3d_set_viewcontext(C, &vc);
901 me= get_mesh(vc.obact);
903 if (me && me->dvert && vc.v3d && vc.rv3d) {
906 view3d_operator_needs_opengl(C);
908 index= view3d_sample_backbuf(&vc, event->mval[0], event->mval[1]);
910 if(index && index<=me->totface) {
911 DerivedMesh *dm= mesh_get_derived_final(vc.scene, vc.obact, CD_MASK_BAREMESH);
913 if(dm->getVertCo==NULL) {
914 BKE_report(op->reports, RPT_WARNING, "The modifier used does not support deformed locations");
917 MFace *mf= ((MFace *)me->mface) + index-1;
918 const int vgroup= vc.obact->actdef - 1;
919 ToolSettings *ts= vc.scene->toolsettings;
923 float len_best= FLT_MAX;
925 mval_f[0]= (float)event->mval[0];
926 mval_f[1]= (float)event->mval[1];
930 float co[3], sco[3], len;
931 const int v_idx= (*(&mf->v1 + fidx));
932 dm->getVertCo(dm, v_idx, co);
933 project_float_noclip(vc.ar, co, sco);
934 len= len_squared_v2v2(mval_f, sco);
941 if(v_idx_best != -1) { /* should always be valid */
942 ts->vgroup_weight= defvert_find_weight(&me->dvert[v_idx_best], vgroup);
951 /* not really correct since the brush didnt change, but redraws the toolbar */
952 WM_main_add_notifier(NC_BRUSH|NA_EDITED, NULL); /* ts->wpaint->paint.brush */
954 return OPERATOR_FINISHED;
957 return OPERATOR_CANCELLED;
961 void PAINT_OT_weight_sample(wmOperatorType *ot)
964 ot->name= "Weight Paint Sample Weight";
965 ot->idname= "PAINT_OT_weight_sample";
968 ot->invoke= weight_sample_invoke;
969 ot->poll= weight_paint_mode_poll;
972 ot->flag= OPTYPE_UNDO;
975 /* samples cursor location, and gives menu with vertex groups to activate */
976 static EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
979 wmWindow *win= CTX_wm_window(C);
980 if(win && win->eventstate) {
984 view3d_set_viewcontext(C, &vc);
985 me= get_mesh(vc.obact);
987 if (me && me->dvert && vc.v3d && vc.rv3d) {
990 view3d_operator_needs_opengl(C);
992 index= view3d_sample_backbuf(&vc, win->eventstate->x - vc.ar->winrct.xmin, win->eventstate->y - vc.ar->winrct.ymin);
994 if(index && index<=me->totface) {
995 const int totgroup= BLI_countlist(&vc.obact->defbase);
997 MFace *mf= ((MFace *)me->mface) + index-1;
998 int fidx= mf->v4 ? 3:2;
999 int *groups= MEM_callocN(totgroup*sizeof(int), "groups");
1003 MDeformVert *dvert= me->dvert + (*(&mf->v1 + fidx));
1004 int i= dvert->totweight;
1006 for(dw= dvert->dw; i > 0; dw++, i--) {
1007 groups[dw->def_nr]= TRUE;
1016 EnumPropertyItem *item= NULL, item_tmp= {0};
1020 for(dg= vc.obact->defbase.first; dg && i<totgroup; i++, dg= dg->next) {
1022 item_tmp.identifier= item_tmp.name= dg->name;
1024 RNA_enum_item_add(&item, &totitem, &item_tmp);
1028 RNA_enum_item_end(&item, &totitem);
1040 return DummyRNA_NULL_items;
1043 static int weight_sample_group_exec(bContext *C, wmOperator *op)
1045 int type= RNA_enum_get(op->ptr, "group");
1047 view3d_set_viewcontext(C, &vc);
1049 vc.obact->actdef= type + 1;
1051 DAG_id_tag_update(&vc.obact->id, OB_RECALC_DATA);
1052 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, vc.obact);
1053 return OPERATOR_FINISHED;
1056 /* TODO, we could make this a menu into OBJECT_OT_vertex_group_set_active rather than its own operator */
1057 void PAINT_OT_weight_sample_group(wmOperatorType *ot)
1059 PropertyRNA *prop= NULL;
1062 ot->name= "Weight Paint Sample Group";
1063 ot->idname= "PAINT_OT_weight_sample_group";
1066 ot->exec= weight_sample_group_exec;
1067 ot->invoke= WM_menu_invoke;
1068 ot->poll= weight_paint_mode_poll;
1071 ot->flag= OPTYPE_UNDO;
1073 /* keyingset to use (dynamic enum) */
1074 prop= RNA_def_enum(ot->srna, "group", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use");
1075 RNA_def_enum_funcs(prop, weight_paint_sample_enum_itemf);
1081 static void do_weight_paint_auto_normalize(MDeformVert *dvert,
1082 int paint_nr, char *map)
1084 // MDeformWeight *dw = dvert->dw;
1085 float sum=0.0f, fac=0.0f, paintw=0.0f;
1091 for (i=0; i<dvert->totweight; i++) {
1092 if (dvert->dw[i].def_nr == paint_nr)
1093 paintw = dvert->dw[i].weight;
1095 if (map[dvert->dw[i].def_nr]) {
1097 if (dvert->dw[i].def_nr != paint_nr)
1098 sum += dvert->dw[i].weight;
1102 if (!tot || sum <= (1.0f - paintw))
1105 fac = sum / (1.0f - paintw);
1106 fac = fac==0.0f ? 1.0f : 1.0f / fac;
1108 for (i=0; i<dvert->totweight; i++) {
1109 if (map[dvert->dw[i].def_nr]) {
1110 if (dvert->dw[i].def_nr != paint_nr)
1111 dvert->dw[i].weight *= fac;
1117 /* the active group should be involved in auto normalize */
1118 static void do_weight_paint_auto_normalize_all_groups(MDeformVert *dvert, char *map, char do_auto_normalize)
1120 // MDeformWeight *dw = dvert->dw;
1121 float sum=0.0f, fac=0.0f;
1124 if (do_auto_normalize == FALSE)
1127 for (i=0; i<dvert->totweight; i++) {
1128 if (map[dvert->dw[i].def_nr]) {
1130 sum += dvert->dw[i].weight;
1134 if (!tot || sum == 1.0f)
1138 fac = fac==0.0f ? 1.0f : 1.0f / fac;
1140 for (i=0; i<dvert->totweight; i++) {
1141 if (map[dvert->dw[i].def_nr]) {
1142 dvert->dw[i].weight *= fac;
1148 See if the current deform vertex has a locked group
1150 static char has_locked_group(MDeformVert *dvert, const char *lock_flags)
1153 for(i = 0; i < dvert->totweight; i++) {
1154 if(lock_flags[dvert->dw[i].def_nr] && dvert->dw[i].weight > 0.0f) {
1161 * gen_lck_flags gets the status of "flag" for each bDeformGroup
1162 *in ob->defbase and returns an array containing them
1164 static char *gen_lock_flags(Object* ob, int defbase_tot)
1166 char is_locked = FALSE;
1168 //int defbase_tot = BLI_countlist(&ob->defbase);
1169 char *lock_flags = MEM_mallocN(defbase_tot*sizeof(char), "defflags");
1170 bDeformGroup *defgroup;
1172 for(i = 0, defgroup = ob->defbase.first; i < defbase_tot && defgroup; defgroup = defgroup->next, i++) {
1173 lock_flags[i] = ((defgroup->flag & DG_LOCK_WEIGHT) != 0);
1174 is_locked |= lock_flags[i];
1180 MEM_freeN(lock_flags);
1184 static int has_locked_group_selected(int defbase_tot, char *defbase_sel, char *lock_flags)
1187 for(i = 0; i < defbase_tot; i++) {
1188 if(defbase_sel[i] && lock_flags[i]) {
1197 static int has_unselected_unlocked_bone_group(int defbase_tot, char *defbase_sel, int selected, char *lock_flags, char *vgroup_validmap)
1200 if(defbase_tot == selected) {
1203 for(i = 0; i < defbase_tot; i++) {
1204 if(vgroup_validmap[i] && !defbase_sel[i] && !lock_flags[i]) {
1213 static void multipaint_selection(MDeformVert *dvert, float change, char *defbase_sel, int defbase_tot)
1218 /* make sure they are all at most 1 after the change */
1219 for(i = 0; i < defbase_tot; i++) {
1220 if(defbase_sel[i]) {
1221 dw = defvert_find_index(dvert, i);
1222 if(dw && dw->weight) {
1223 val = dw->weight * change;
1225 /* TODO: when the change is reduced, you need to recheck
1226 * the earlier values to make sure they are not 0
1227 * (precision error) */
1228 change = 1.0f/dw->weight;
1230 /* the value should never reach zero while multi-painting if it
1231 * was nonzero beforehand */
1238 /* apply the valid change */
1239 for(i = 0; i < defbase_tot; i++) {
1240 if(defbase_sel[i]) {
1241 dw = defvert_find_index(dvert, i);
1242 if(dw && dw->weight) {
1243 dw->weight = dw->weight * change;
1249 /* move all change onto valid, unchanged groups. If there is change left over,
1251 * assumes there are valid groups to shift weight onto */
1252 static float redistribute_change(MDeformVert *ndv, char *change_status, int changeme, int changeto, float totchange, float total_valid, char do_auto_normalize)
1260 /* assume there is no change until you see one */
1262 /* change each group by the same amount each time */
1263 change = totchange/total_valid;
1264 for(i = 0; i < ndv->totweight && total_valid && totchange; i++) {
1266 /* change only the groups with a valid status */
1267 if(change_status[ndw->def_nr] == changeme) {
1268 oldval = ndw->weight;
1269 /* if auto normalize is active, don't worry about upper bounds */
1270 if(do_auto_normalize == FALSE && ndw->weight + change > 1) {
1271 totchange -= 1-ndw->weight;
1273 /* stop the changes to this group */
1274 change_status[ndw->def_nr] = changeto;
1277 else if(ndw->weight + change < 0) { /* check the lower bound */
1278 totchange -= ndw->weight;
1280 change_status[ndw->def_nr] = changeto;
1283 else {/* a perfectly valid change occurred to ndw->weight */
1284 totchange -= change;
1285 ndw->weight += change;
1287 /* see if there was a change */
1288 if(oldval != ndw->weight) {
1293 /* don't go again if there was no change, if there is no valid group,
1294 * or there is no change left */
1295 } while(was_change && total_valid && totchange);
1300 /* observe the changes made to the weights of groups.
1301 * make sure all locked groups on the vertex have the same deformation
1302 * by moving the changes made to groups onto other unlocked groups */
1303 static void enforce_locks(MDeformVert *odv, MDeformVert *ndv, int defbase_tot,
1304 const char *lock_flags, const char *vgroup_validmap, char do_auto_normalize)
1306 float totchange = 0.0f;
1307 float totchange_allowed = 0.0f;
1310 int total_valid = 0;
1311 int total_changed = 0;
1315 MDeformWeight *ndw2;
1316 MDeformWeight *odw2;
1317 int designatedw = -1;
1318 int designatedw_changed = FALSE;
1320 char *change_status;
1321 char new_weight_has_zero = FALSE;
1323 if(!lock_flags || !has_locked_group(ndv, lock_flags)) {
1326 /* record if a group was changed, unlocked and not changed, or locked */
1327 change_status = MEM_callocN(sizeof(char)*defbase_tot, "unlocked_unchanged");
1329 for(i = 0; i < defbase_tot; i++) {
1330 ndw = defvert_find_index(ndv, i);
1331 odw = defvert_find_index(odv, i);
1332 /* the weights are zero, so we can assume a lot */
1334 if (!lock_flags[i] && vgroup_validmap[i]){
1335 defvert_verify_index(odv, i);
1336 defvert_verify_index(ndv, i);
1338 change_status[i] = 1; /* can be altered while redistributing */
1342 /* locked groups should not be changed */
1344 ndw->weight = odw->weight;
1346 else if(ndw->weight != odw->weight) { /* changed groups are handled here */
1347 totchange += ndw->weight - odw->weight;
1348 change_status[i] = 2; /* was altered already */
1350 if(ndw->weight == 0) {
1351 new_weight_has_zero = TRUE;
1353 else if(designatedw == -1){
1356 } /* unchanged, unlocked bone groups are handled here */
1357 else if (vgroup_validmap[i]){
1358 totchange_allowed += ndw->weight;
1360 change_status[i] = 1; /* can be altered while redistributing */
1363 /* if there was any change, redistribute it */
1365 /* auto normalize will allow weights to temporarily go above 1 in redistribution */
1366 if(vgroup_validmap && total_changed < 0 && total_valid) {
1367 totchange_allowed = total_valid;
1369 /* there needs to be change allowed, or you should not bother */
1370 if(totchange_allowed) {
1371 /* the way you modify the unlocked+unchanged groups is different depending
1372 * on whether or not you are painting the weight(s) up or down */
1374 totchange_allowed = total_valid - totchange_allowed;
1377 totchange_allowed *= -1;
1380 if(fabsf(totchange_allowed) < fabsf(totchange)) {
1381 /* this amount goes back onto the changed, unlocked weights */
1382 left_over = fabsf(fabsf(totchange) - fabsf(totchange_allowed));
1388 /* all of the change will be permitted */
1389 totchange_allowed = -totchange;
1391 /* move the weight evenly between the allowed groups, move excess back onto the used groups based on the change */
1392 totchange_allowed = redistribute_change(ndv, change_status, 1, -1, totchange_allowed, total_valid, do_auto_normalize);
1393 left_over += totchange_allowed;
1395 /* more than one nonzero weights were changed with the same ratio, so keep them changed that way! */
1396 if(total_changed > 1 && !new_weight_has_zero && designatedw >= 0) {
1397 /* this dw is special, it is used as a base to determine how to change the others */
1398 ndw = defvert_find_index(ndv, designatedw);
1399 odw = defvert_find_index(odv, designatedw);
1400 storedw = ndw->weight;
1401 for(i = 0; i < ndv->totweight; i++) {
1402 if(change_status[ndw->def_nr] == 2) {
1405 if(!designatedw_changed) {
1406 ndw->weight = (totchange_allowed + odw->weight + odw2->weight)/(1 + ndw2->weight/ndw->weight);
1407 designatedw_changed = TRUE;
1409 ndw2->weight = ndw->weight * ndw2->weight / storedw;
1413 /* a weight was changed to zero, only one weight was changed,
1414 * or designatedw is still -1 put weight back as evenly as possible */
1416 redistribute_change(ndv, change_status, 2, -2, left_over, total_changed, do_auto_normalize);
1421 /* reset the weights */
1422 for(i = 0; i < ndv->totweight; i++) {
1423 ndv->dw[i].weight = odv->dw[i].weight;
1428 MEM_freeN(change_status);
1431 /* multi-paint's initial, potential change is computed here based on the user's stroke */
1432 static float get_mp_change(MDeformVert *odv, char *defbase_sel, float brush_change)
1434 float selwsum = 0.0f;
1437 for(i=0; i < odv->totweight; i++) {
1438 if(defbase_sel[(dw= &odv->dw[i])->def_nr]) {
1439 selwsum += dw->weight;
1442 if(selwsum && selwsum+brush_change > 0) {
1443 return (selwsum+brush_change)/selwsum;
1448 /* change the weights back to the wv's weights
1449 * it assumes you already have the correct pointer index */
1450 static void reset_to_prev(MDeformVert *wv, MDeformVert *dv)
1455 for(i = 0; i < dv->totweight; i++) {
1457 w= defvert_find_index(wv, d->def_nr);
1458 /* if there was no w when there is a d, then the old weight was 0 */
1459 d->weight = w ? w->weight : 0.0f;
1463 static void clamp_weights(MDeformVert *dvert)
1466 for (i = 0; i < dvert->totweight; i++) {
1467 CLAMP((dvert->dw+i)->weight, 0.0f, 1.0f);
1471 /* struct to avoid passing many args each call to do_weight_paint_vertex()
1472 * this _could_ be made a part of the operators 'WPaintData' struct, or at
1473 * least a member, but for now keep its own struct, initialized on every
1474 * paint stroke update - campbell */
1475 typedef struct WeightPaintInfo {
1479 /* both must add up to 'defbase_tot' */
1480 int defbase_tot_sel;
1481 int defbase_tot_unsel;
1483 int vgroup_mirror; /* mirror group or -1 */
1485 char *lock_flags; /* boolean array for locked bones,
1486 * length of defbase_tot */
1487 char *defbase_sel; /* boolean array for selected bones,
1488 * length of defbase_tot */
1490 char *vgroup_validmap; /* same as WeightPaintData.vgroup_validmap,
1491 * only added here for convenience */
1495 char do_auto_normalize;
1498 /* fresh start to make multi-paint and locking modular */
1499 /* returns TRUE if it thinks you need to reset the weights due to
1500 * normalizing while multi-painting */
1501 static int apply_mp_locks_normalize(Mesh *me, const WeightPaintInfo *wpi,
1503 MDeformWeight *dw, MDeformWeight *tdw,
1504 float change, float oldChange,
1505 float oldw, float neww)
1507 MDeformVert *dv= me->dvert+index;
1508 MDeformVert dv_test= {NULL};
1510 dv_test.dw= MEM_dupallocN(dv->dw);
1511 dv_test.flag = dv->flag;
1512 dv_test.totweight = dv->totweight;
1513 /* do not multi-paint if a locked group is selected or the active group is locked
1514 * !lock_flags[dw->def_nr] helps if nothing is selected, but active group is locked */
1515 if( (wpi->lock_flags == NULL) ||
1516 ((wpi->lock_flags[dw->def_nr] == FALSE) &&
1517 has_locked_group_selected(wpi->defbase_tot, wpi->defbase_sel, wpi->lock_flags) == FALSE))
1519 if(wpi->do_multipaint && wpi->defbase_tot_sel > 1) {
1520 if(change && change!=1) {
1521 multipaint_selection(dv, change, wpi->defbase_sel, wpi->defbase_tot);
1524 else { /* this lets users paint normally, but don't let them paint locked groups */
1530 enforce_locks(&dv_test, dv, wpi->defbase_tot, wpi->lock_flags, wpi->vgroup_validmap, wpi->do_auto_normalize);
1532 do_weight_paint_auto_normalize_all_groups(dv, wpi->vgroup_validmap, wpi->do_auto_normalize);
1534 if(oldChange && wpi->do_multipaint && wpi->defbase_tot_sel > 1) {
1535 if(tdw->weight != oldw) {
1537 if(tdw->weight <= oldw) {
1538 MEM_freeN(dv_test.dw);
1543 if(tdw->weight >= oldw) {
1544 MEM_freeN(dv_test.dw);
1550 MEM_freeN(dv_test.dw);
1554 /* within the current dvert index, get the dw that is selected and has a weight
1555 * above 0, this helps multi-paint */
1556 static int get_first_selected_nonzero_weight(MDeformVert *dvert, char *defbase_sel)
1560 for(i=0; i< dvert->totweight; i++) {
1562 if(defbase_sel[dw->def_nr] && dw->weight > 0) {
1570 static char *wpaint_make_validmap(Object *ob);
1573 static void do_weight_paint_vertex( /* vars which remain the same for every vert */
1574 VPaint *wp, Object *ob, const WeightPaintInfo *wpi,
1575 /* vars which change on each stroke */
1576 int index, float alpha, float paintweight
1581 MDeformWeight *dw, *uw;
1582 int vgroup= ob->actdef-1;
1584 if(wp->flag & VP_ONLYVGROUP) {
1585 dw= defvert_find_index(me->dvert+index, vgroup);
1586 uw= defvert_find_index(wp->wpaint_prev+index, vgroup);
1589 dw= defvert_verify_index(me->dvert+index, vgroup);
1590 uw= defvert_verify_index(wp->wpaint_prev+index, vgroup);
1592 if(dw==NULL || uw==NULL)
1595 /* TODO: De-duplicate the simple weight paint - jason */
1596 /* ... or not, since its <10 SLOC - campbell */
1598 /* If there are no locks or multipaint,
1599 * then there is no need to run the more complicated checks */
1600 if( (wpi->do_multipaint == FALSE || wpi->defbase_tot_sel <= 1) &&
1601 (wpi->lock_flags == NULL || has_locked_group(&me->dvert[index], wpi->lock_flags) == FALSE))
1603 wpaint_blend(wp, dw, uw, alpha, paintweight, wpi->do_flip, FALSE);
1604 do_weight_paint_auto_normalize_all_groups(me->dvert+index, wpi->vgroup_validmap, wpi->do_auto_normalize);
1606 if(me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */
1607 int j= mesh_get_x_mirror_vert(ob, index);
1609 /* copy, not paint again */
1610 uw= defvert_verify_index(me->dvert+j, (wpi->vgroup_mirror != -1) ? wpi->vgroup_mirror : vgroup);
1612 uw->weight= dw->weight;
1614 do_weight_paint_auto_normalize_all_groups(me->dvert+j, wpi->vgroup_validmap, wpi->do_auto_normalize);
1619 /* use locks and/or multipaint */
1624 float oldChange = 0;
1626 MDeformWeight *tdw = NULL, *tuw;
1627 MDeformVert dv= {NULL};
1630 wpaint_blend(wp, dw, uw, alpha, paintweight, wpi->do_flip, wpi->do_multipaint && wpi->defbase_tot_sel >1);
1634 /* setup multi-paint */
1635 if(wpi->defbase_tot_sel > 1 && wpi->do_multipaint) {
1636 dv.dw= MEM_dupallocN((me->dvert+index)->dw);
1637 dv.flag = me->dvert[index].flag;
1638 dv.totweight = (me->dvert+index)->totweight;
1641 change = get_mp_change(wp->wpaint_prev+index, wpi->defbase_sel, neww - oldw);
1644 i = get_first_selected_nonzero_weight(me->dvert+index, wpi->defbase_sel);
1646 tdw = &(me->dvert[index].dw[i]);
1647 tuw = defvert_verify_index(wp->wpaint_prev+index, tdw->def_nr);
1653 if(change && tuw->weight && tuw->weight * change) {
1654 if(tdw->weight != tuw->weight) {
1655 oldChange = tdw->weight/tuw->weight;
1656 testw = tuw->weight*change;
1657 if( testw > tuw->weight ) {
1658 if(change > oldChange) {
1659 /* reset the weights and use the new change */
1660 reset_to_prev(wp->wpaint_prev+index, me->dvert+index);
1663 /* the old change was more significant, so set
1664 * the change to 0 so that it will not do another multi-paint */
1669 if(change < oldChange) {
1670 reset_to_prev(wp->wpaint_prev+index, me->dvert+index);
1684 if(apply_mp_locks_normalize(me, wpi, index, dw, tdw, change, oldChange, oldw, neww)) {
1685 reset_to_prev(&dv, me->dvert+index);
1692 /* dvert may have been altered greatly */
1693 dw = defvert_find_index(me->dvert+index, vgroup);
1695 if(me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */
1696 int j= mesh_get_x_mirror_vert(ob, index);
1698 /* copy, not paint again */
1699 uw= defvert_verify_index(me->dvert+j, (wpi->vgroup_mirror != -1) ? wpi->vgroup_mirror : vgroup);
1701 //uw->weight= dw->weight;
1703 apply_mp_locks_normalize(me, wpi, j, uw, tdw, change, oldChange, oldw, neww);
1710 /* *************** set wpaint operator ****************** */
1712 static int set_wpaint(bContext *C, wmOperator *UNUSED(op)) /* toggle */
1714 Object *ob= CTX_data_active_object(C);
1715 Scene *scene= CTX_data_scene(C);
1716 VPaint *wp= scene->toolsettings->wpaint;
1720 if(ob->id.lib || me==NULL) return OPERATOR_PASS_THROUGH;
1722 if(ob->mode & OB_MODE_WEIGHT_PAINT) ob->mode &= ~OB_MODE_WEIGHT_PAINT;
1723 else ob->mode |= OB_MODE_WEIGHT_PAINT;
1726 /* Weightpaint works by overriding colors in mesh,
1727 * so need to make sure we recalc on enter and
1728 * exit (exit needs doing regardless because we
1731 DAG_id_tag_update(&me->id, 0);
1733 if(ob->mode & OB_MODE_WEIGHT_PAINT) {
1737 wp= scene->toolsettings->wpaint= new_vpaint(1);
1739 paint_init(&wp->paint, PAINT_CURSOR_WEIGHT_PAINT);
1740 paint_cursor_start(C, weight_paint_poll);
1742 mesh_octree_table(ob, NULL, NULL, 's');
1744 /* verify if active weight group is also active bone */
1745 par= modifiers_isDeformedByArmature(ob);
1746 if(par && (par->mode & OB_MODE_POSE)) {
1747 bArmature *arm= par->data;
1750 ED_vgroup_select_by_name(ob, arm->act_bone->name);
1754 mesh_octree_table(NULL, NULL, NULL, 'e');
1755 mesh_mirrtopo_table(NULL, 'e');
1758 WM_event_add_notifier(C, NC_SCENE|ND_MODE, scene);
1760 return OPERATOR_FINISHED;
1763 /* for switching to/from mode */
1764 static int paint_poll_test(bContext *C)
1766 if(CTX_data_edit_object(C))
1768 if(CTX_data_active_object(C)==NULL)
1773 void PAINT_OT_weight_paint_toggle(wmOperatorType *ot)
1777 ot->name= "Weight Paint Mode";
1778 ot->idname= "PAINT_OT_weight_paint_toggle";
1781 ot->exec= set_wpaint;
1782 ot->poll= paint_poll_test;
1785 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1789 /* ************ weight paint operator ********** */
1795 float *vertexcosnos;
1798 /*variables for auto normalize*/
1800 char *vgroup_validmap; /*stores if vgroups tie to deforming bones or not*/
1805 static char *wpaint_make_validmap(Object *ob)
1809 char *vgroup_validmap;
1810 GHash *gh = BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "wpaint_make_validmap gh");
1813 /*add all names to a hash table*/
1814 for (dg=ob->defbase.first, i=0; dg; dg=dg->next, i++) {
1815 BLI_ghash_insert(gh, dg->name, NULL);
1821 vgroup_validmap= MEM_callocN(i, "wpaint valid map");
1823 /*now loop through the armature modifiers and identify deform bones*/
1824 for (md = ob->modifiers.first; md; md= !md->next && step1 ? (step1=0), modifiers_getVirtualModifierList(ob) : md->next) {
1825 if (!(md->mode & (eModifierMode_Realtime|eModifierMode_Virtual)))
1828 if (md->type == eModifierType_Armature)
1830 ArmatureModifierData *amd= (ArmatureModifierData*) md;
1832 if(amd->object && amd->object->pose) {
1833 bPose *pose= amd->object->pose;
1836 for (chan=pose->chanbase.first; chan; chan=chan->next) {
1837 if (chan->bone->flag & BONE_NO_DEFORM)
1840 if (BLI_ghash_haskey(gh, chan->name)) {
1841 BLI_ghash_remove(gh, chan->name, NULL, NULL);
1842 BLI_ghash_insert(gh, chan->name, SET_INT_IN_POINTER(1));
1849 /*add all names to a hash table*/
1850 for (dg=ob->defbase.first, i=0; dg; dg=dg->next, i++) {
1851 if (BLI_ghash_lookup(gh, dg->name) != NULL) {
1852 vgroup_validmap[i] = TRUE;
1856 BLI_ghash_free(gh, NULL, NULL);
1858 return vgroup_validmap;
1861 static int wpaint_stroke_test_start(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1863 Scene *scene= CTX_data_scene(C);
1864 struct PaintStroke *stroke = op->customdata;
1865 ToolSettings *ts= CTX_data_tool_settings(C);
1866 VPaint *wp= ts->wpaint;
1867 Object *ob= CTX_data_active_object(C);
1868 struct WPaintData *wpd;
1870 float mat[4][4], imat[4][4];
1872 if(scene->obedit) return OPERATOR_CANCELLED;
1875 if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH;
1877 /* if nothing was added yet, we make dverts and a vertex deform group */
1879 ED_vgroup_data_create(&me->id);
1880 WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
1883 /* make mode data storage */
1884 wpd= MEM_callocN(sizeof(struct WPaintData), "WPaintData");
1885 paint_stroke_set_mode_data(stroke, wpd);
1886 view3d_set_viewcontext(C, &wpd->vc);
1887 wpd->vgroup_mirror= -1;
1889 /*set up auto-normalize, and generate map for detecting which
1890 vgroups affect deform bones*/
1891 wpd->auto_normalize = ts->auto_normalize;
1892 wpd->defbase_tot = BLI_countlist(&ob->defbase);
1893 wpd->lock_flags = gen_lock_flags(ob, wpd->defbase_tot);
1894 if (wpd->auto_normalize || ts->multipaint || wpd->lock_flags)
1895 wpd->vgroup_validmap = wpaint_make_validmap(ob);
1897 // if(qual & LR_CTRLKEY) {
1898 // sample_wpaint(scene, ar, v3d, 0);
1901 // if(qual & LR_SHIFTKEY) {
1902 // sample_wpaint(scene, ar, v3d, 1);
1906 /* ALLOCATIONS! no return after this line */
1907 /* painting on subsurfs should give correct points too, this returns me->totvert amount */
1908 wpd->vertexcosnos= mesh_get_mapped_verts_nors(scene, ob);
1909 wpd->indexar= get_indexarray(me);
1910 copy_wpaint_prev(wp, me->dvert, me->totvert);
1912 /* this happens on a Bone select, when no vgroup existed yet */
1915 if((modob = modifiers_isDeformedByArmature(ob))) {
1916 Bone *actbone= ((bArmature *)modob->data)->act_bone;
1918 bPoseChannel *pchan= get_pose_channel(modob->pose, actbone->name);
1921 bDeformGroup *dg= defgroup_find_name(ob, pchan->name);
1923 dg= ED_vgroup_add_name(ob, pchan->name); /* sets actdef */
1925 ob->actdef= 1 + defgroup_find_index(ob, dg);
1930 if(ob->defbase.first==NULL) {
1934 // if(ob->lay & v3d->lay); else error("Active object is not in this layer");
1936 /* imat for normals */
1937 mul_m4_m4m4(mat, ob->obmat, wpd->vc.rv3d->viewmat);
1938 invert_m4_m4(imat, mat);
1939 copy_m3_m4(wpd->wpimat, imat);
1941 /* if mirror painting, find the other group */
1942 if(me->editflag & ME_EDIT_MIRROR_X) {
1943 wpaint_mirror_vgroup_ensure(ob, &wpd->vgroup_mirror);
1949 static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
1951 ToolSettings *ts= CTX_data_tool_settings(C);
1952 VPaint *wp= ts->wpaint;
1953 Brush *brush = paint_brush(&wp->paint);
1954 struct WPaintData *wpd= paint_stroke_mode_data(stroke);
1961 int totindex, index, totw;
1963 float mval[2], pressure;
1966 /* intentionally dont initialize as NULL, make sure we initialize all members below */
1967 WeightPaintInfo wpi;
1969 /* cannot paint if there is no stroke data */
1971 /* XXX: force a redraw here, since even though we can't paint,
1972 * at least view won't freeze until stroke ends */
1973 ED_region_tag_redraw(CTX_wm_region(C));
1980 indexar= wpd->indexar;
1982 view3d_operator_needs_opengl(C);
1984 /* load projection matrix */
1985 mul_m4_m4m4(mat, ob->obmat, vc->rv3d->persmat);
1987 pressure = RNA_float_get(itemptr, "pressure");
1988 RNA_float_get_array(itemptr, "mouse", mval);
1989 mval[0]-= vc->ar->winrct.xmin;
1990 mval[1]-= vc->ar->winrct.ymin;
1994 /* *** setup WeightPaintInfo - pass onto do_weight_paint_vertex *** */
1995 wpi.defbase_tot= wpd->defbase_tot;
1996 wpi.defbase_sel= MEM_mallocN(wpi.defbase_tot*sizeof(char), "wpi.defbase_sel");
1997 wpi.defbase_tot_sel= get_selected_defgroups(ob, wpi.defbase_sel, wpi.defbase_tot);
1998 if(wpi.defbase_tot_sel == 0 && ob->actdef) wpi.defbase_tot_sel = 1;
1999 wpi.defbase_tot_unsel= wpi.defbase_tot - wpi.defbase_tot_sel;
2000 wpi.vgroup_mirror= wpd->vgroup_mirror;
2001 wpi.lock_flags= wpd->lock_flags;
2002 wpi.vgroup_validmap= wpd->vgroup_validmap;
2003 wpi.do_flip= RNA_boolean_get(itemptr, "pen_flip");
2004 wpi.do_multipaint= (ts->multipaint != 0);
2005 wpi.do_auto_normalize= (ts->auto_normalize != 0);
2006 /* *** done setting up WeightPaintInfo *** */
2010 swap_m4m4(wpd->vc.rv3d->persmat, mat);
2012 use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
2014 /* which faces are involved */
2015 if(wp->flag & VP_AREA) {
2016 /* Ugly hack, to avoid drawing vertex index when getting the face index buffer - campbell */
2017 me->editflag &= ~ME_EDIT_VERT_SEL;
2018 totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush_size(brush));
2019 me->editflag |= use_vert_sel ? ME_EDIT_VERT_SEL : 0;
2022 indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]);
2023 if(indexar[0]) totindex= 1;
2027 if(wp->flag & VP_COLINDEX) {
2028 for(index=0; index<totindex; index++) {
2029 if(indexar[index] && indexar[index]<=me->totface) {
2030 MFace *mface= ((MFace *)me->mface) + (indexar[index]-1);
2032 if(mface->mat_nr!=ob->actcol-1) {
2039 if((me->editflag & ME_EDIT_PAINT_MASK) && me->mface) {
2040 for(index=0; index<totindex; index++) {
2041 if(indexar[index] && indexar[index]<=me->totface) {
2042 MFace *mface= ((MFace *)me->mface) + (indexar[index]-1);
2044 if((mface->flag & ME_FACE_SEL)==0) {
2051 /* make sure each vertex gets treated only once */
2052 /* and calculate filter weight */
2054 if(brush->vertexpaint_tool==VP_BLUR)
2057 paintweight= ts->vgroup_weight;
2059 for(index=0; index<totindex; index++) {
2060 if(indexar[index] && indexar[index]<=me->totface) {
2061 MFace *mface= me->mface + (indexar[index]-1);
2064 me->dvert[mface->v1].flag = (me->mvert[mface->v1].flag & SELECT);
2065 me->dvert[mface->v2].flag = (me->mvert[mface->v2].flag & SELECT);
2066 me->dvert[mface->v3].flag = (me->mvert[mface->v3].flag & SELECT);
2067 if(mface->v4) me->dvert[mface->v4].flag = (me->mvert[mface->v4].flag & SELECT);
2070 me->dvert[mface->v1].flag= 1;
2071 me->dvert[mface->v2].flag= 1;
2072 me->dvert[mface->v3].flag= 1;
2073 if(mface->v4) me->dvert[mface->v4].flag= 1;
2076 if(brush->vertexpaint_tool==VP_BLUR) {
2077 MDeformWeight *dw, *(*dw_func)(MDeformVert *, const int);
2079 if(wp->flag & VP_ONLYVGROUP)
2080 dw_func= (MDeformWeight *(*)(MDeformVert *, const int))defvert_find_index;
2082 dw_func= defvert_verify_index;
2084 dw= dw_func(me->dvert+mface->v1, ob->actdef-1);
2085 if(dw) {paintweight+= dw->weight; totw++;}
2086 dw= dw_func(me->dvert+mface->v2, ob->actdef-1);
2087 if(dw) {paintweight+= dw->weight; totw++;}
2088 dw= dw_func(me->dvert+mface->v3, ob->actdef-1);
2089 if(dw) {paintweight+= dw->weight; totw++;}
2091 dw= dw_func(me->dvert+mface->v4, ob->actdef-1);
2092 if(dw) {paintweight+= dw->weight; totw++;}
2098 if(brush->vertexpaint_tool==VP_BLUR)
2099 paintweight/= (float)totw;
2101 for(index=0; index<totindex; index++) {
2103 if(indexar[index] && indexar[index]<=me->totface) {
2104 MFace *mf= me->mface + (indexar[index]-1);
2105 unsigned int fidx= mf->v4 ? 3:2;;
2107 int vidx= *(&mf->v1 + fidx);
2109 if(me->dvert[vidx].flag) {
2110 alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*vidx, mval, pressure);
2112 do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight);
2114 me->dvert[vidx].flag= 0;
2121 /* *** free wpi members */
2122 MEM_freeN(wpi.defbase_sel);
2123 /* *** dont freeing wpi members */
2126 swap_m4m4(vc->rv3d->persmat, mat);
2128 DAG_id_tag_update(ob->data, 0);
2129 ED_region_tag_redraw(vc->ar);
2132 static void wpaint_stroke_done(bContext *C, struct PaintStroke *stroke)
2134 ToolSettings *ts= CTX_data_tool_settings(C);
2135 Object *ob= CTX_data_active_object(C);
2136 struct WPaintData *wpd= paint_stroke_mode_data(stroke);
2139 if(wpd->vertexcosnos)
2140 MEM_freeN(wpd->vertexcosnos);
2141 MEM_freeN(wpd->indexar);
2143 if (wpd->vgroup_validmap)
2144 MEM_freeN(wpd->vgroup_validmap);
2146 MEM_freeN(wpd->lock_flags);
2151 /* frees prev buffer */
2152 copy_wpaint_prev(ts->wpaint, NULL, 0);
2154 /* and particles too */
2155 if(ob->particlesystem.first) {
2156 ParticleSystem *psys;
2159 for(psys= ob->particlesystem.first; psys; psys= psys->next) {
2160 for(i=0; i<PSYS_TOT_VG; i++) {
2161 if(psys->vgroup[i]==ob->actdef) {
2162 psys->recalc |= PSYS_RECALC_RESET;
2169 DAG_id_tag_update(ob->data, 0);
2173 static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
2176 op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start,
2177 wpaint_stroke_update_step,
2178 wpaint_stroke_done, event->type);
2180 /* add modal handler */
2181 WM_event_add_modal_handler(C, op);
2183 op->type->modal(C, op, event);
2185 return OPERATOR_RUNNING_MODAL;
2188 static int wpaint_cancel(bContext *C, wmOperator *op)
2190 paint_stroke_cancel(C, op);
2192 return OPERATOR_CANCELLED;
2195 void PAINT_OT_weight_paint(wmOperatorType *ot)
2199 ot->name= "Weight Paint";
2200 ot->idname= "PAINT_OT_weight_paint";
2203 ot->invoke= wpaint_invoke;
2204 ot->modal= paint_stroke_modal;
2205 /* ot->exec= vpaint_exec; <-- needs stroke property */
2206 ot->poll= weight_paint_poll;
2207 ot->cancel= wpaint_cancel;
2210 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
2212 RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
2215 static int weight_paint_set_exec(bContext *C, wmOperator *UNUSED(op))
2217 struct Scene *scene= CTX_data_scene(C);
2218 Object *obact = CTX_data_active_object(C);
2220 wpaint_fill(scene->toolsettings->wpaint, obact, scene->toolsettings->vgroup_weight);
2221 ED_region_tag_redraw(CTX_wm_region(C)); /* XXX - should redraw all 3D views */
2222 return OPERATOR_FINISHED;
2225 void PAINT_OT_weight_set(wmOperatorType *ot)
2228 ot->name= "Set Weight";
2229 ot->idname= "PAINT_OT_weight_set";
2232 ot->exec= weight_paint_set_exec;
2233 ot->poll= mask_paint_poll; /* it was facemask_paint_poll */
2236 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2239 /* ************ set / clear vertex paint mode ********** */
2242 static int set_vpaint(bContext *C, wmOperator *op) /* toggle */
2244 Object *ob= CTX_data_active_object(C);
2245 Scene *scene= CTX_data_scene(C);
2246 VPaint *vp= scene->toolsettings->vpaint;
2251 if(me==NULL || object_data_is_libdata(ob)) {
2252 ob->mode &= ~OB_MODE_VERTEX_PAINT;
2253 return OPERATOR_PASS_THROUGH;
2256 if(me && me->mcol==NULL) make_vertexcol(ob);
2258 /* toggle: end vpaint */
2259 if(ob->mode & OB_MODE_VERTEX_PAINT) {
2261 ob->mode &= ~OB_MODE_VERTEX_PAINT;
2264 ob->mode |= OB_MODE_VERTEX_PAINT;
2265 /* Turn off weight painting */
2266 if (ob->mode & OB_MODE_WEIGHT_PAINT)
2270 vp= scene->toolsettings->vpaint= new_vpaint(0);
2272 paint_cursor_start(C, vertex_paint_poll);
2274 paint_init(&vp->paint, PAINT_CURSOR_VERTEX_PAINT);
2278 /* update modifier stack for mapping requirements */
2279 DAG_id_tag_update(&me->id, 0);
2281 WM_event_add_notifier(C, NC_SCENE|ND_MODE, scene);
2283 return OPERATOR_FINISHED;
2286 void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
2290 ot->name= "Vertex Paint Mode";
2291 ot->idname= "PAINT_OT_vertex_paint_toggle";
2294 ot->exec= set_vpaint;
2295 ot->poll= paint_poll_test;
2298 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2303 /* ********************** vertex paint operator ******************* */
2305 /* Implementation notes:
2308 - validate context (add mcol)
2309 - create customdata storage
2310 - call paint once (mouse click)
2314 - for every mousemove, apply vertex paint
2315 - exit on mouse release, free customdata
2316 (return OPERATOR_FINISHED also removes handler and operator)
2319 - implement a stroke event (or mousemove with past positons)
2320 - revise whether op->customdata should be added in object, in set_vpaint
2324 typedef struct VPaintData {
2326 unsigned int paintcol;
2328 float *vertexcosnos;
2332 static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *UNUSED(event))
2334 ToolSettings *ts= CTX_data_tool_settings(C);
2335 struct PaintStroke *stroke = op->customdata;
2336 VPaint *vp= ts->vpaint;
2337 struct VPaintData *vpd;
2338 Object *ob= CTX_data_active_object(C);
2340 float mat[4][4], imat[4][4];
2342 /* context checks could be a poll() */
2344 if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH;
2346 if(me->mcol==NULL) make_vertexcol(ob);
2347 if(me->mcol==NULL) return OPERATOR_CANCELLED;
2349 /* make mode data storage */
2350 vpd= MEM_callocN(sizeof(struct VPaintData), "VPaintData");
2351 paint_stroke_set_mode_data(stroke, vpd);
2352 view3d_set_viewcontext(C, &vpd->vc);
2354 vpd->vertexcosnos= mesh_get_mapped_verts_nors(vpd->vc.scene, ob);
2355 vpd->indexar= get_indexarray(me);
2356 vpd->paintcol= vpaint_get_current_col(vp);
2359 copy_vpaint_prev(vp, (unsigned int *)me->mcol, me->totface);
2361 /* some old cruft to sort out later */
2362 mul_m4_m4m4(mat, ob->obmat, vpd->vc.rv3d->viewmat);
2363 invert_m4_m4(imat, mat);
2364 copy_m3_m4(vpd->vpimat, imat);
2369 static void vpaint_paint_face(VPaint *vp, VPaintData *vpd, Object *ob, int index, const float mval[2], float pressure, int UNUSED(flip))
2371 ViewContext *vc = &vpd->vc;
2372 Brush *brush = paint_brush(&vp->paint);
2373 Mesh *me = get_mesh(ob);
2374 MFace *mface= ((MFace*)me->mface) + index;
2375 unsigned int *mcol= ((unsigned int*)me->mcol) + 4*index;
2376 unsigned int *mcolorig= ((unsigned int*)vp->vpaint_prev) + 4*index;
2380 if((vp->flag & VP_COLINDEX && mface->mat_nr!=ob->actcol-1) ||
2381 ((me->editflag & ME_EDIT_PAINT_MASK) && !(mface->flag & ME_FACE_SEL)))
2384 if(brush->vertexpaint_tool==VP_BLUR) {
2385 unsigned int fcol1= mcol_blend( mcol[0], mcol[1], 128);
2387 unsigned int fcol2= mcol_blend( mcol[2], mcol[3], 128);
2388 vpd->paintcol= mcol_blend( fcol1, fcol2, 128);
2391 vpd->paintcol= mcol_blend( mcol[2], fcol1, 170);
2396 for(i = 0; i < (mface->v4 ? 4 : 3); ++i) {
2397 alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*(&mface->v1)[i], mval, pressure);
2399 vpaint_blend(vp, mcol+i, mcolorig+i, vpd->paintcol, (int)(alpha*255.0f));
2403 static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
2405 ToolSettings *ts= CTX_data_tool_settings(C);
2406 struct VPaintData *vpd = paint_stroke_mode_data(stroke);
2407 VPaint *vp= ts->vpaint;
2408 Brush *brush = paint_brush(&vp->paint);
2409 ViewContext *vc= &vpd->vc;
2410 Object *ob= vc->obact;
2413 int *indexar= vpd->indexar;
2414 int totindex, index, flip;
2415 float pressure, mval[2];
2417 RNA_float_get_array(itemptr, "mouse", mval);
2418 flip = RNA_boolean_get(itemptr, "pen_flip");
2419 pressure = RNA_float_get(itemptr, "pressure");
2421 view3d_operator_needs_opengl(C);
2423 /* load projection matrix */
2424 mul_m4_m4m4(mat, ob->obmat, vc->rv3d->persmat);
2426 mval[0]-= vc->ar->winrct.xmin;
2427 mval[1]-= vc->ar->winrct.ymin;
2430 /* which faces are involved */
2431 if(vp->flag & VP_AREA) {
2432 totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush_size(brush));
2435 indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]);
2436 if(indexar[0]) totindex= 1;
2440 swap_m4m4(vc->rv3d->persmat, mat);
2442 for(index=0; index<totindex; index++) {
2443 if(indexar[index] && indexar[index]<=me->totface)
2444 vpaint_paint_face(vp, vpd, ob, indexar[index]-1, mval, pressure, flip);
2447 swap_m4m4(vc->rv3d->persmat, mat);
2449 /* was disabled because it is slow, but necessary for blur */
2450 if(brush->vertexpaint_tool == VP_BLUR)
2451 do_shared_vertexcol(me);
2453 ED_region_tag_redraw(vc->ar);
2455 DAG_id_tag_update(ob->data, 0);
2458 static void vpaint_stroke_done(bContext *C, struct PaintStroke *stroke)
2460 ToolSettings *ts= CTX_data_tool_settings(C);
2461 struct VPaintData *vpd= paint_stroke_mode_data(stroke);
2463 if(vpd->vertexcosnos)
2464 MEM_freeN(vpd->vertexcosnos);
2465 MEM_freeN(vpd->indexar);
2467 /* frees prev buffer */
2468 copy_vpaint_prev(ts->vpaint, NULL, 0);
2473 static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
2476 op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start,
2477 vpaint_stroke_update_step,
2478 vpaint_stroke_done, event->type);
2480 /* add modal handler */
2481 WM_event_add_modal_handler(C, op);
2483 op->type->modal(C, op, event);
2485 return OPERATOR_RUNNING_MODAL;
2488 static int vpaint_cancel(bContext *C, wmOperator *op)
2490 paint_stroke_cancel(C, op);
2492 return OPERATOR_CANCELLED;
2495 void PAINT_OT_vertex_paint(wmOperatorType *ot)
2498 ot->name= "Vertex Paint";
2499 ot->idname= "PAINT_OT_vertex_paint";
2502 ot->invoke= vpaint_invoke;
2503 ot->modal= paint_stroke_modal;
2504 /* ot->exec= vpaint_exec; <-- needs stroke property */
2505 ot->poll= vertex_paint_poll;
2506 ot->cancel= vpaint_cancel;
2509 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
2511 RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
2514 /* ********************** weight from bones operator ******************* */
2516 static int weight_from_bones_poll(bContext *C)
2518 Object *ob= CTX_data_active_object(C);
2520 return (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && modifiers_isDeformedByArmature(ob));
2523 static int weight_from_bones_exec(bContext *C, wmOperator *op)
2525 Scene *scene= CTX_data_scene(C);
2526 Object *ob= CTX_data_active_object(C);
2527 Object *armob= modifiers_isDeformedByArmature(ob);
2529 int type= RNA_enum_get(op->ptr, "type");
2531 create_vgroups_from_armature(op->reports, scene, ob, armob, type, (me->editflag & ME_EDIT_MIRROR_X));
2533 DAG_id_tag_update(&me->id, 0);
2534 WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
2536 return OPERATOR_FINISHED;
2539 void PAINT_OT_weight_from_bones(wmOperatorType *ot)
2541 static EnumPropertyItem type_items[]= {
2542 {ARM_GROUPS_AUTO, "AUTOMATIC", 0, "Automatic", "Automatic weights froms bones"},
2543 {ARM_GROUPS_ENVELOPE, "ENVELOPES", 0, "From Envelopes", "Weights from envelopes with user defined radius"},
2544 {0, NULL, 0, NULL, NULL}};
2547 ot->name= "Weight from Bones";
2548 ot->idname= "PAINT_OT_weight_from_bones";
2551 ot->exec= weight_from_bones_exec;
2552 ot->invoke= WM_menu_invoke;
2553 ot->poll= weight_from_bones_poll;
2556 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2559 ot->prop= RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights");