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)
394 MDeformWeight *dw, *uw;
397 int vgroup, vgroup_mirror= -1;
403 if(me==NULL || me->totface==0 || me->dvert==NULL || !me->mface) return;
405 selected= (me->editflag & ME_EDIT_PAINT_MASK);
407 use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
409 indexar= get_indexarray(me);
413 for(index=0, mf= me->mface; index<me->totface; index++, mf++) {
414 if((mf->flag & ME_FACE_SEL)==0)
417 indexar[index]= index+1;
421 for(index=0; index<me->totface; index++)
422 indexar[index]= index+1;
425 vgroup= ob->actdef-1;
427 /* if mirror painting, find the other group */
428 if(me->editflag & ME_EDIT_MIRROR_X) {
429 wpaint_mirror_vgroup_ensure(ob, &vgroup_mirror);
432 copy_wpaint_prev(wp, me->dvert, me->totvert);
434 for(index=0; index<me->totface; index++) {
435 if(indexar[index] && indexar[index]<=me->totface) {
436 MFace *mf= &me->mface[indexar[index]-1];
437 unsigned int fidx= mf->v4 ? 3:2;
440 unsigned int vidx= *(&mf->v1 + fidx);
442 if(!me->dvert[vidx].flag) {
443 if(use_vert_sel && !(me->mvert[vidx].flag & SELECT)) {
447 dw= defvert_verify_index(&me->dvert[vidx], vgroup);
449 uw= defvert_verify_index(wp->wpaint_prev+vidx, vgroup);
450 uw->weight= dw->weight; /* set the undo weight */
451 dw->weight= paintweight;
453 if(me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */
454 int j= mesh_get_x_mirror_vert(ob, vidx);
456 /* copy, not paint again */
457 if(vgroup_mirror != -1) {
458 dw= defvert_verify_index(me->dvert+j, vgroup_mirror);
459 uw= defvert_verify_index(wp->wpaint_prev+j, vgroup_mirror);
461 dw= defvert_verify_index(me->dvert+j, vgroup);
462 uw= defvert_verify_index(wp->wpaint_prev+j, vgroup);
464 uw->weight= dw->weight; /* set the undo weight */
465 dw->weight= paintweight;
469 me->dvert[vidx].flag= 1;
478 MDeformVert *dv= me->dvert;
479 for(index= me->totvert; index != 0; index--, dv++) {
485 copy_wpaint_prev(wp, NULL, 0);
487 DAG_id_tag_update(&me->id, 0);
490 /* XXX: should be re-implemented as a vertex/weight paint 'color correct' operator
492 void vpaint_dogamma(Scene *scene)
494 VPaint *vp= scene->toolsettings->vpaint;
499 unsigned char *cp, gamtab[256];
504 if(!(ob->mode & OB_MODE_VERTEX_PAINT)) return;
505 if(me==0 || me->mcol==0 || me->totface==0) return;
508 for(a=0; a<256; a++) {
510 fac= ((float)a)/255.0;
511 fac= vp->mul*pow( fac, igam);
515 if(temp<=0) gamtab[a]= 0;
516 else if(temp>=255) gamtab[a]= 255;
517 else gamtab[a]= temp;
521 cp= (unsigned char *)me->mcol;
524 cp[1]= gamtab[ cp[1] ];
525 cp[2]= gamtab[ cp[2] ];
526 cp[3]= gamtab[ cp[3] ];
533 static unsigned int mcol_blend(unsigned int col1, unsigned int col2, int fac)
535 char *cp1, *cp2, *cp;
539 if(fac==0) return col1;
540 if(fac>=255) return col2;
549 cp[1]= (mfac*cp1[1]+fac*cp2[1])/255;
550 cp[2]= (mfac*cp1[2]+fac*cp2[2])/255;
551 cp[3]= (mfac*cp1[3]+fac*cp2[3])/255;
556 static unsigned int mcol_add(unsigned int col1, unsigned int col2, int fac)
558 char *cp1, *cp2, *cp;
562 if(fac==0) return col1;
569 temp= cp1[1] + ((fac*cp2[1])/255);
570 if(temp>254) cp[1]= 255; else cp[1]= temp;
571 temp= cp1[2] + ((fac*cp2[2])/255);
572 if(temp>254) cp[2]= 255; else cp[2]= temp;
573 temp= cp1[3] + ((fac*cp2[3])/255);
574 if(temp>254) cp[3]= 255; else cp[3]= temp;
579 static unsigned int mcol_sub(unsigned int col1, unsigned int col2, int fac)
581 char *cp1, *cp2, *cp;
585 if(fac==0) return col1;
592 temp= cp1[1] - ((fac*cp2[1])/255);
593 if(temp<0) cp[1]= 0; else cp[1]= temp;
594 temp= cp1[2] - ((fac*cp2[2])/255);
595 if(temp<0) cp[2]= 0; else cp[2]= temp;
596 temp= cp1[3] - ((fac*cp2[3])/255);
597 if(temp<0) cp[3]= 0; else cp[3]= temp;
602 static unsigned int mcol_mul(unsigned int col1, unsigned int col2, int fac)
604 char *cp1, *cp2, *cp;
608 if(fac==0) return col1;
616 /* first mul, then blend the fac */
618 cp[1]= (mfac*cp1[1] + fac*((cp2[1]*cp1[1])/255) )/255;
619 cp[2]= (mfac*cp1[2] + fac*((cp2[2]*cp1[2])/255) )/255;
620 cp[3]= (mfac*cp1[3] + fac*((cp2[3]*cp1[3])/255) )/255;
626 static unsigned int mcol_lighten(unsigned int col1, unsigned int col2, int fac)
628 char *cp1, *cp2, *cp;
632 if(fac==0) return col1;
633 if(fac>=255) return col2;
641 /* See if are lighter, if so mix, else dont do anything.
642 if the paint col is darker then the original, then ignore */
643 if (cp1[1]+cp1[2]+cp1[3] > cp2[1]+cp2[2]+cp2[3])
647 cp[1]= (mfac*cp1[1]+fac*cp2[1])/255;
648 cp[2]= (mfac*cp1[2]+fac*cp2[2])/255;
649 cp[3]= (mfac*cp1[3]+fac*cp2[3])/255;
654 static unsigned int mcol_darken(unsigned int col1, unsigned int col2, int fac)
656 char *cp1, *cp2, *cp;
660 if(fac==0) return col1;
661 if(fac>=255) return col2;
669 /* See if were darker, if so mix, else dont do anything.
670 if the paint col is brighter then the original, then ignore */
671 if (cp1[1]+cp1[2]+cp1[3] < cp2[1]+cp2[2]+cp2[3])
675 cp[1]= (mfac*cp1[1]+fac*cp2[1])/255;
676 cp[2]= (mfac*cp1[2]+fac*cp2[2])/255;
677 cp[3]= (mfac*cp1[3]+fac*cp2[3])/255;
681 static void vpaint_blend(VPaint *vp, unsigned int *col, unsigned int *colorig, unsigned int paintcol, int alpha)
683 Brush *brush = paint_brush(&vp->paint);
685 if(brush->vertexpaint_tool==VP_MIX || brush->vertexpaint_tool==VP_BLUR) *col= mcol_blend( *col, paintcol, alpha);
686 else if(brush->vertexpaint_tool==VP_ADD) *col= mcol_add( *col, paintcol, alpha);
687 else if(brush->vertexpaint_tool==VP_SUB) *col= mcol_sub( *col, paintcol, alpha);
688 else if(brush->vertexpaint_tool==VP_MUL) *col= mcol_mul( *col, paintcol, alpha);
689 else if(brush->vertexpaint_tool==VP_LIGHTEN) *col= mcol_lighten( *col, paintcol, alpha);
690 else if(brush->vertexpaint_tool==VP_DARKEN) *col= mcol_darken( *col, paintcol, alpha);
692 /* if no spray, clip color adding with colorig & orig alpha */
693 if((vp->flag & VP_SPRAY)==0) {
694 unsigned int testcol=0, a;
697 alpha= (int)(255.0f*brush_alpha(brush));
699 if(brush->vertexpaint_tool==VP_MIX || brush->vertexpaint_tool==VP_BLUR) testcol= mcol_blend( *colorig, paintcol, alpha);
700 else if(brush->vertexpaint_tool==VP_ADD) testcol= mcol_add( *colorig, paintcol, alpha);
701 else if(brush->vertexpaint_tool==VP_SUB) testcol= mcol_sub( *colorig, paintcol, alpha);
702 else if(brush->vertexpaint_tool==VP_MUL) testcol= mcol_mul( *colorig, paintcol, alpha);
703 else if(brush->vertexpaint_tool==VP_LIGHTEN) testcol= mcol_lighten( *colorig, paintcol, alpha);
704 else if(brush->vertexpaint_tool==VP_DARKEN) testcol= mcol_darken( *colorig, paintcol, alpha);
707 ct= (char *)&testcol;
712 if( cp[a]<ct[a] ) cp[a]= ct[a];
713 else if( cp[a]>co[a] ) cp[a]= co[a];
716 if( cp[a]<co[a] ) cp[a]= co[a];
717 else if( cp[a]>ct[a] ) cp[a]= ct[a];
724 static int sample_backbuf_area(ViewContext *vc, int *indexar, int totface, int x, int y, float size)
729 /* brecht: disabled this because it obviously failes for
730 brushes with size > 64, why is this here? */
731 /*if(size>64.0) size= 64.0;*/
733 ibuf= view3d_read_backbuf(vc, x-size, y-size, x+size, y+size);
735 unsigned int *rt= ibuf->rect;
737 memset(indexar, 0, sizeof(int)*(totface+1));
739 size= ibuf->x*ibuf->y;
743 index= WM_framebuffer_to_index(*rt);
744 if(index>0 && index<=totface)
751 for(a=1; a<=totface; a++) {
752 if(indexar[a]) indexar[tot++]= a;
761 static float calc_vp_alpha_dl(VPaint *vp, ViewContext *vc, float vpimat[][3], float *vert_nor, const float mval[2], float pressure)
763 Brush *brush = paint_brush(&vp->paint);
764 float fac, fac_2, size, dx, dy;
767 const int radius= brush_size(brush);
769 project_int_noclip(vc->ar, vert_nor, vertco);
770 dx= mval[0]-vertco[0];
771 dy= mval[1]-vertco[1];
773 if (brush_use_size_pressure(brush))
774 size = pressure * radius;
778 fac_2= dx*dx + dy*dy;
779 if(fac_2 > size*size) return 0.f;
782 alpha= brush_alpha(brush) * brush_curve_strength_clamp(brush, fac, size);
784 if (brush_use_alpha_pressure(brush))
787 if(vp->flag & VP_NORMALS) {
788 float *no= vert_nor+3;
791 fac= vpimat[2][0]*no[0]+vpimat[2][1]*no[1]+vpimat[2][2]*no[2];
793 dx= vpimat[0][0]*no[0]+vpimat[0][1]*no[1]+vpimat[0][2]*no[2];
794 dy= vpimat[1][0]*no[0]+vpimat[1][1]*no[1]+vpimat[1][2]*no[2];
796 alpha*= fac/sqrtf(dx*dx + dy*dy + fac*fac);
804 static void wpaint_blend(VPaint *wp, MDeformWeight *dw, MDeformWeight *uw, float alpha, float paintval, int flip, int multipaint)
806 Brush *brush = paint_brush(&wp->paint);
807 int tool = brush->vertexpaint_tool;
809 if(dw==NULL || uw==NULL) return;
814 paintval = 1.f - paintval; break;
820 tool= VP_DARKEN; break;
822 tool= VP_LIGHTEN; break;
826 if(tool==VP_MIX || tool==VP_BLUR)
827 dw->weight = paintval*alpha + dw->weight*(1.0f-alpha);
828 else if(tool==VP_ADD)
829 dw->weight += paintval*alpha;
830 else if(tool==VP_SUB)
831 dw->weight -= paintval*alpha;
832 else if(tool==VP_MUL)
833 /* first mul, then blend the fac */
834 dw->weight = ((1.0f-alpha) + alpha*paintval)*dw->weight;
835 else if(tool==VP_LIGHTEN) {
836 if (dw->weight < paintval)
837 dw->weight = paintval*alpha + dw->weight*(1.0f-alpha);
838 } else if(tool==VP_DARKEN) {
839 if (dw->weight > paintval)
840 dw->weight = paintval*alpha + dw->weight*(1.0f-alpha);
842 /* delay clamping until the end so multi-paint can function when the active group is at the limits */
843 if(multipaint == FALSE) {
844 CLAMP(dw->weight, 0.0f, 1.0f);
847 /* if no spray, clip result with orig weight & orig alpha */
848 if((wp->flag & VP_SPRAY)==0) {
851 alpha= brush_alpha(brush);
852 if(tool==VP_MIX || tool==VP_BLUR)
853 testw = paintval*alpha + uw->weight*(1.0f-alpha);
854 else if(tool==VP_ADD)
855 testw = uw->weight + paintval*alpha;
856 else if(tool==VP_SUB)
857 testw = uw->weight - paintval*alpha;
858 else if(tool==VP_MUL)
859 /* first mul, then blend the fac */
860 testw = ((1.0f-alpha) + alpha*paintval)*uw->weight;
861 else if(tool==VP_LIGHTEN) {
862 if (uw->weight < paintval)
863 testw = paintval*alpha + uw->weight*(1.0f-alpha);
866 } else if(tool==VP_DARKEN) {
867 if (uw->weight > paintval)
868 testw = paintval*alpha + uw->weight*(1.0f-alpha);
873 if(multipaint == FALSE) {
874 CLAMP(testw, 0.0f, 1.0f);
875 if( testw<uw->weight ) {
876 if(dw->weight < testw) dw->weight= testw;
877 else if(dw->weight > uw->weight) dw->weight= uw->weight;
880 if(dw->weight > testw) dw->weight= testw;
881 else if(dw->weight < uw->weight) dw->weight= uw->weight;
888 /* ----------------------------------------------------- */
891 /* sets wp->weight to the closest weight value to vertex */
892 /* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */
893 static int weight_sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
899 view3d_set_viewcontext(C, &vc);
900 me= get_mesh(vc.obact);
902 if (me && me->dvert && vc.v3d && vc.rv3d) {
905 view3d_operator_needs_opengl(C);
907 index= view3d_sample_backbuf(&vc, event->mval[0], event->mval[1]);
909 if(index && index<=me->totface) {
910 DerivedMesh *dm= mesh_get_derived_final(vc.scene, vc.obact, CD_MASK_BAREMESH);
912 if(dm->getVertCo==NULL) {
913 BKE_report(op->reports, RPT_WARNING, "The modifier used does not support deformed locations");
916 MFace *mf= ((MFace *)me->mface) + index-1;
917 const int vgroup= vc.obact->actdef - 1;
918 ToolSettings *ts= vc.scene->toolsettings;
922 float len_best= FLT_MAX;
924 mval_f[0]= (float)event->mval[0];
925 mval_f[1]= (float)event->mval[1];
929 float co[3], sco[3], len;
930 const int v_idx= (*(&mf->v1 + fidx));
931 dm->getVertCo(dm, v_idx, co);
932 project_float_noclip(vc.ar, co, sco);
933 len= len_squared_v2v2(mval_f, sco);
940 if(v_idx_best != -1) { /* should always be valid */
941 ts->vgroup_weight= defvert_find_weight(&me->dvert[v_idx_best], vgroup);
950 /* not really correct since the brush didnt change, but redraws the toolbar */
951 WM_main_add_notifier(NC_BRUSH|NA_EDITED, NULL); /* ts->wpaint->paint.brush */
953 return OPERATOR_FINISHED;
956 return OPERATOR_CANCELLED;
960 void PAINT_OT_weight_sample(wmOperatorType *ot)
963 ot->name= "Weight Paint Sample Weight";
964 ot->idname= "PAINT_OT_weight_sample";
967 ot->invoke= weight_sample_invoke;
968 ot->poll= weight_paint_mode_poll;
971 ot->flag= OPTYPE_UNDO;
974 /* samples cursor location, and gives menu with vertex groups to activate */
975 static EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
978 wmWindow *win= CTX_wm_window(C);
979 if(win && win->eventstate) {
983 view3d_set_viewcontext(C, &vc);
984 me= get_mesh(vc.obact);
986 if (me && me->dvert && vc.v3d && vc.rv3d) {
989 view3d_operator_needs_opengl(C);
991 index= view3d_sample_backbuf(&vc, win->eventstate->x - vc.ar->winrct.xmin, win->eventstate->y - vc.ar->winrct.ymin);
993 if(index && index<=me->totface) {
994 const int totgroup= BLI_countlist(&vc.obact->defbase);
996 MFace *mf= ((MFace *)me->mface) + index-1;
997 unsigned int fidx= mf->v4 ? 3:2;
998 int *groups= MEM_callocN(totgroup*sizeof(int), "groups");
1002 MDeformVert *dvert= me->dvert + (*(&mf->v1 + fidx));
1003 int i= dvert->totweight;
1005 for(dw= dvert->dw; i > 0; dw++, i--) {
1006 groups[dw->def_nr]= TRUE;
1015 EnumPropertyItem *item= NULL, item_tmp= {0};
1019 for(dg= vc.obact->defbase.first; dg && i<totgroup; i++, dg= dg->next) {
1021 item_tmp.identifier= item_tmp.name= dg->name;
1023 RNA_enum_item_add(&item, &totitem, &item_tmp);
1027 RNA_enum_item_end(&item, &totitem);
1039 return DummyRNA_NULL_items;
1042 static int weight_sample_group_exec(bContext *C, wmOperator *op)
1044 int type= RNA_enum_get(op->ptr, "group");
1046 view3d_set_viewcontext(C, &vc);
1048 vc.obact->actdef= type + 1;
1050 DAG_id_tag_update(&vc.obact->id, OB_RECALC_DATA);
1051 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, vc.obact);
1052 return OPERATOR_FINISHED;
1055 /* TODO, we could make this a menu into OBJECT_OT_vertex_group_set_active rather than its own operator */
1056 void PAINT_OT_weight_sample_group(wmOperatorType *ot)
1058 PropertyRNA *prop= NULL;
1061 ot->name= "Weight Paint Sample Group";
1062 ot->idname= "PAINT_OT_weight_sample_group";
1065 ot->exec= weight_sample_group_exec;
1066 ot->invoke= WM_menu_invoke;
1067 ot->poll= weight_paint_mode_poll;
1070 ot->flag= OPTYPE_UNDO;
1072 /* keyingset to use (dynamic enum) */
1073 prop= RNA_def_enum(ot->srna, "group", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use");
1074 RNA_def_enum_funcs(prop, weight_paint_sample_enum_itemf);
1080 static void do_weight_paint_auto_normalize(MDeformVert *dvert,
1081 int paint_nr, char *map)
1083 // MDeformWeight *dw = dvert->dw;
1084 float sum=0.0f, fac=0.0f, paintw=0.0f;
1090 for (i=0; i<dvert->totweight; i++) {
1091 if (dvert->dw[i].def_nr == paint_nr)
1092 paintw = dvert->dw[i].weight;
1094 if (map[dvert->dw[i].def_nr]) {
1096 if (dvert->dw[i].def_nr != paint_nr)
1097 sum += dvert->dw[i].weight;
1101 if (!tot || sum <= (1.0f - paintw))
1104 fac = sum / (1.0f - paintw);
1105 fac = fac==0.0f ? 1.0f : 1.0f / fac;
1107 for (i=0; i<dvert->totweight; i++) {
1108 if (map[dvert->dw[i].def_nr]) {
1109 if (dvert->dw[i].def_nr != paint_nr)
1110 dvert->dw[i].weight *= fac;
1116 /* the active group should be involved in auto normalize */
1117 static void do_weight_paint_auto_normalize_all_groups(MDeformVert *dvert, char *map, char do_auto_normalize)
1119 // MDeformWeight *dw = dvert->dw;
1120 float sum=0.0f, fac=0.0f;
1123 if (do_auto_normalize == FALSE)
1126 for (i=0; i<dvert->totweight; i++) {
1127 if (map[dvert->dw[i].def_nr]) {
1129 sum += dvert->dw[i].weight;
1133 if (!tot || sum == 1.0f)
1137 fac = fac==0.0f ? 1.0f : 1.0f / fac;
1139 for (i=0; i<dvert->totweight; i++) {
1140 if (map[dvert->dw[i].def_nr]) {
1141 dvert->dw[i].weight *= fac;
1147 See if the current deform vertex has a locked group
1149 static char has_locked_group(MDeformVert *dvert, const char *lock_flags)
1152 for(i = 0; i < dvert->totweight; i++) {
1153 if(lock_flags[dvert->dw[i].def_nr] && dvert->dw[i].weight > 0.0f) {
1160 * gen_lck_flags gets the status of "flag" for each bDeformGroup
1161 *in ob->defbase and returns an array containing them
1163 static char *gen_lock_flags(Object* ob, int defbase_tot)
1165 char is_locked = FALSE;
1167 //int defbase_tot = BLI_countlist(&ob->defbase);
1168 char *lock_flags = MEM_mallocN(defbase_tot*sizeof(char), "defflags");
1169 bDeformGroup *defgroup;
1171 for(i = 0, defgroup = ob->defbase.first; i < defbase_tot && defgroup; defgroup = defgroup->next, i++) {
1172 lock_flags[i] = ((defgroup->flag & DG_LOCK_WEIGHT) != 0);
1173 is_locked |= lock_flags[i];
1179 MEM_freeN(lock_flags);
1183 static int has_locked_group_selected(int defbase_tot, char *defbase_sel, char *lock_flags)
1186 for(i = 0; i < defbase_tot; i++) {
1187 if(defbase_sel[i] && lock_flags[i]) {
1196 static int has_unselected_unlocked_bone_group(int defbase_tot, char *defbase_sel, int selected, char *lock_flags, char *vgroup_validmap)
1199 if(defbase_tot == selected) {
1202 for(i = 0; i < defbase_tot; i++) {
1203 if(vgroup_validmap[i] && !defbase_sel[i] && !lock_flags[i]) {
1212 static void multipaint_selection(MDeformVert *dvert, float change, char *defbase_sel, int defbase_tot)
1217 /* make sure they are all at most 1 after the change */
1218 for(i = 0; i < defbase_tot; i++) {
1219 if(defbase_sel[i]) {
1220 dw = defvert_find_index(dvert, i);
1221 if(dw && dw->weight) {
1222 val = dw->weight * change;
1224 /* TODO: when the change is reduced, you need to recheck
1225 * the earlier values to make sure they are not 0
1226 * (precision error) */
1227 change = 1.0f/dw->weight;
1229 /* the value should never reach zero while multi-painting if it
1230 * was nonzero beforehand */
1237 /* apply the valid change */
1238 for(i = 0; i < defbase_tot; i++) {
1239 if(defbase_sel[i]) {
1240 dw = defvert_find_index(dvert, i);
1241 if(dw && dw->weight) {
1242 dw->weight = dw->weight * change;
1248 /* move all change onto valid, unchanged groups. If there is change left over,
1250 * assumes there are valid groups to shift weight onto */
1251 static float redistribute_change(MDeformVert *ndv, char *change_status, int changeme, int changeto, float totchange, float total_valid, char do_auto_normalize)
1259 /* assume there is no change until you see one */
1261 /* change each group by the same amount each time */
1262 change = totchange/total_valid;
1263 for(i = 0; i < ndv->totweight && total_valid && totchange; i++) {
1265 /* change only the groups with a valid status */
1266 if(change_status[ndw->def_nr] == changeme) {
1267 oldval = ndw->weight;
1268 /* if auto normalize is active, don't worry about upper bounds */
1269 if(do_auto_normalize == FALSE && ndw->weight + change > 1) {
1270 totchange -= 1-ndw->weight;
1272 /* stop the changes to this group */
1273 change_status[ndw->def_nr] = changeto;
1276 else if(ndw->weight + change < 0) { /* check the lower bound */
1277 totchange -= ndw->weight;
1279 change_status[ndw->def_nr] = changeto;
1282 else {/* a perfectly valid change occurred to ndw->weight */
1283 totchange -= change;
1284 ndw->weight += change;
1286 /* see if there was a change */
1287 if(oldval != ndw->weight) {
1292 /* don't go again if there was no change, if there is no valid group,
1293 * or there is no change left */
1294 } while(was_change && total_valid && totchange);
1299 /* observe the changes made to the weights of groups.
1300 * make sure all locked groups on the vertex have the same deformation
1301 * by moving the changes made to groups onto other unlocked groups */
1302 static void enforce_locks(MDeformVert *odv, MDeformVert *ndv, int defbase_tot,
1303 const char *lock_flags, const char *vgroup_validmap, char do_auto_normalize)
1305 float totchange = 0.0f;
1306 float totchange_allowed = 0.0f;
1309 int total_valid = 0;
1310 int total_changed = 0;
1314 MDeformWeight *ndw2;
1315 MDeformWeight *odw2;
1316 int designatedw = -1;
1317 int designatedw_changed = FALSE;
1319 char *change_status;
1320 char new_weight_has_zero = FALSE;
1322 if(!lock_flags || !has_locked_group(ndv, lock_flags)) {
1325 /* record if a group was changed, unlocked and not changed, or locked */
1326 change_status = MEM_callocN(sizeof(char)*defbase_tot, "unlocked_unchanged");
1328 for(i = 0; i < defbase_tot; i++) {
1329 ndw = defvert_find_index(ndv, i);
1330 odw = defvert_find_index(odv, i);
1331 /* the weights are zero, so we can assume a lot */
1333 if (!lock_flags[i] && vgroup_validmap[i]){
1334 defvert_verify_index(odv, i);
1335 defvert_verify_index(ndv, i);
1337 change_status[i] = 1; /* can be altered while redistributing */
1341 /* locked groups should not be changed */
1343 ndw->weight = odw->weight;
1345 else if(ndw->weight != odw->weight) { /* changed groups are handled here */
1346 totchange += ndw->weight - odw->weight;
1347 change_status[i] = 2; /* was altered already */
1349 if(ndw->weight == 0) {
1350 new_weight_has_zero = TRUE;
1352 else if(designatedw == -1){
1355 } /* unchanged, unlocked bone groups are handled here */
1356 else if (vgroup_validmap[i]){
1357 totchange_allowed += ndw->weight;
1359 change_status[i] = 1; /* can be altered while redistributing */
1362 /* if there was any change, redistribute it */
1364 /* auto normalize will allow weights to temporarily go above 1 in redistribution */
1365 if(vgroup_validmap && total_changed < 0 && total_valid) {
1366 totchange_allowed = total_valid;
1368 /* there needs to be change allowed, or you should not bother */
1369 if(totchange_allowed) {
1370 /* the way you modify the unlocked+unchanged groups is different depending
1371 * on whether or not you are painting the weight(s) up or down */
1373 totchange_allowed = total_valid - totchange_allowed;
1376 totchange_allowed *= -1;
1379 if(fabsf(totchange_allowed) < fabsf(totchange)) {
1380 /* this amount goes back onto the changed, unlocked weights */
1381 left_over = fabsf(fabsf(totchange) - fabsf(totchange_allowed));
1387 /* all of the change will be permitted */
1388 totchange_allowed = -totchange;
1390 /* move the weight evenly between the allowed groups, move excess back onto the used groups based on the change */
1391 totchange_allowed = redistribute_change(ndv, change_status, 1, -1, totchange_allowed, total_valid, do_auto_normalize);
1392 left_over += totchange_allowed;
1394 /* more than one nonzero weights were changed with the same ratio, so keep them changed that way! */
1395 if(total_changed > 1 && !new_weight_has_zero && designatedw >= 0) {
1396 /* this dw is special, it is used as a base to determine how to change the others */
1397 ndw = defvert_find_index(ndv, designatedw);
1398 odw = defvert_find_index(odv, designatedw);
1399 storedw = ndw->weight;
1400 for(i = 0; i < ndv->totweight; i++) {
1401 if(change_status[ndw->def_nr] == 2) {
1404 if(!designatedw_changed) {
1405 ndw->weight = (totchange_allowed + odw->weight + odw2->weight)/(1.0f + ndw2->weight/ndw->weight);
1406 designatedw_changed = TRUE;
1408 ndw2->weight = ndw->weight * ndw2->weight / storedw;
1412 /* a weight was changed to zero, only one weight was changed,
1413 * or designatedw is still -1 put weight back as evenly as possible */
1415 redistribute_change(ndv, change_status, 2, -2, left_over, total_changed, do_auto_normalize);
1420 /* reset the weights */
1422 MDeformWeight *dw_old= odv->dw;
1423 MDeformWeight *dw_new= ndv->dw;
1425 for (i= odv->totweight; i != 0; i--, dw_old++, dw_new++) {
1426 dw_new->weight= dw_old->weight;
1431 MEM_freeN(change_status);
1434 /* multi-paint's initial, potential change is computed here based on the user's stroke */
1435 static float get_mp_change(MDeformVert *odv, char *defbase_sel, float brush_change)
1437 float selwsum = 0.0f;
1439 MDeformWeight *dw= odv->dw;
1441 for (i= odv->totweight; i != 0; i--, dw++) {
1442 if(defbase_sel[dw->def_nr]) {
1443 selwsum += dw->weight;
1446 if(selwsum && selwsum+brush_change > 0) {
1447 return (selwsum+brush_change)/selwsum;
1452 /* change the weights back to the wv's weights
1453 * it assumes you already have the correct pointer index */
1454 static void reset_to_prev(MDeformVert *wv, MDeformVert *dvert)
1456 MDeformWeight *dw= dvert->dw;
1459 for (i= dvert->totweight; i != 0; i--, dw++) {
1460 w= defvert_find_index(wv, dw->def_nr);
1461 /* if there was no w when there is a d, then the old weight was 0 */
1462 dw->weight = w ? w->weight : 0.0f;
1466 static void clamp_weights(MDeformVert *dvert)
1468 MDeformWeight *dw= dvert->dw;
1470 for (i= dvert->totweight; i != 0; i--, dw++) {
1471 CLAMP(dw->weight, 0.0f, 1.0f);
1475 /* struct to avoid passing many args each call to do_weight_paint_vertex()
1476 * this _could_ be made a part of the operators 'WPaintData' struct, or at
1477 * least a member, but for now keep its own struct, initialized on every
1478 * paint stroke update - campbell */
1479 typedef struct WeightPaintInfo {
1483 /* both must add up to 'defbase_tot' */
1484 int defbase_tot_sel;
1485 int defbase_tot_unsel;
1487 int vgroup_mirror; /* mirror group or -1 */
1489 char *lock_flags; /* boolean array for locked bones,
1490 * length of defbase_tot */
1491 char *defbase_sel; /* boolean array for selected bones,
1492 * length of defbase_tot */
1494 char *vgroup_validmap; /* same as WeightPaintData.vgroup_validmap,
1495 * only added here for convenience */
1499 char do_auto_normalize;
1502 /* fresh start to make multi-paint and locking modular */
1503 /* returns TRUE if it thinks you need to reset the weights due to
1504 * normalizing while multi-painting */
1505 static int apply_mp_locks_normalize(Mesh *me, const WeightPaintInfo *wpi,
1506 const unsigned int index,
1507 MDeformWeight *dw, MDeformWeight *tdw,
1508 float change, float oldChange,
1509 float oldw, float neww)
1511 MDeformVert *dv= &me->dvert[index];
1512 MDeformVert dv_test= {NULL};
1514 dv_test.dw= MEM_dupallocN(dv->dw);
1515 dv_test.flag = dv->flag;
1516 dv_test.totweight = dv->totweight;
1517 /* do not multi-paint if a locked group is selected or the active group is locked
1518 * !lock_flags[dw->def_nr] helps if nothing is selected, but active group is locked */
1519 if( (wpi->lock_flags == NULL) ||
1520 ((wpi->lock_flags[dw->def_nr] == FALSE) &&
1521 has_locked_group_selected(wpi->defbase_tot, wpi->defbase_sel, wpi->lock_flags) == FALSE))
1523 if(wpi->do_multipaint && wpi->defbase_tot_sel > 1) {
1524 if(change && change!=1) {
1525 multipaint_selection(dv, change, wpi->defbase_sel, wpi->defbase_tot);
1528 else { /* this lets users paint normally, but don't let them paint locked groups */
1534 enforce_locks(&dv_test, dv, wpi->defbase_tot, wpi->lock_flags, wpi->vgroup_validmap, wpi->do_auto_normalize);
1536 do_weight_paint_auto_normalize_all_groups(dv, wpi->vgroup_validmap, wpi->do_auto_normalize);
1538 if(oldChange && wpi->do_multipaint && wpi->defbase_tot_sel > 1) {
1539 if(tdw->weight != oldw) {
1541 if(tdw->weight <= oldw) {
1542 MEM_freeN(dv_test.dw);
1547 if(tdw->weight >= oldw) {
1548 MEM_freeN(dv_test.dw);
1554 MEM_freeN(dv_test.dw);
1558 /* within the current dvert index, get the dw that is selected and has a weight
1559 * above 0, this helps multi-paint */
1560 static int get_first_selected_nonzero_weight(MDeformVert *dvert, char *defbase_sel)
1563 MDeformWeight *dw= dvert->dw;
1564 for(i=0; i< dvert->totweight; i++, dw++) {
1565 if(defbase_sel[dw->def_nr] && dw->weight > 0.0f) {
1573 static char *wpaint_make_validmap(Object *ob);
1576 static void do_weight_paint_vertex( /* vars which remain the same for every vert */
1577 VPaint *wp, Object *ob, const WeightPaintInfo *wpi,
1578 /* vars which change on each stroke */
1579 const unsigned int index, float alpha, float paintweight
1584 MDeformWeight *dw, *uw;
1585 int vgroup= ob->actdef-1;
1587 if(wp->flag & VP_ONLYVGROUP) {
1588 dw= defvert_find_index(&me->dvert[index], vgroup);
1589 uw= defvert_find_index(wp->wpaint_prev+index, vgroup);
1592 dw= defvert_verify_index(&me->dvert[index], vgroup);
1593 uw= defvert_verify_index(wp->wpaint_prev+index, vgroup);
1595 if(dw==NULL || uw==NULL)
1598 /* TODO: De-duplicate the simple weight paint - jason */
1599 /* ... or not, since its <10 SLOC - campbell */
1601 /* If there are no locks or multipaint,
1602 * then there is no need to run the more complicated checks */
1603 if( (wpi->do_multipaint == FALSE || wpi->defbase_tot_sel <= 1) &&
1604 (wpi->lock_flags == NULL || has_locked_group(&me->dvert[index], wpi->lock_flags) == FALSE))
1606 wpaint_blend(wp, dw, uw, alpha, paintweight, wpi->do_flip, FALSE);
1607 do_weight_paint_auto_normalize_all_groups(&me->dvert[index], wpi->vgroup_validmap, wpi->do_auto_normalize);
1609 if(me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */
1610 int j= mesh_get_x_mirror_vert(ob, index);
1612 /* copy, not paint again */
1613 uw= defvert_verify_index(me->dvert+j, (wpi->vgroup_mirror != -1) ? wpi->vgroup_mirror : vgroup);
1615 uw->weight= dw->weight;
1617 do_weight_paint_auto_normalize_all_groups(me->dvert+j, wpi->vgroup_validmap, wpi->do_auto_normalize);
1622 /* use locks and/or multipaint */
1627 float oldChange = 0;
1629 MDeformWeight *tdw = NULL, *tuw;
1630 MDeformVert dv= {NULL};
1633 wpaint_blend(wp, dw, uw, alpha, paintweight, wpi->do_flip, wpi->do_multipaint && wpi->defbase_tot_sel >1);
1637 /* setup multi-paint */
1638 if(wpi->defbase_tot_sel > 1 && wpi->do_multipaint) {
1639 dv.dw= MEM_dupallocN(me->dvert[index].dw);
1640 dv.flag = me->dvert[index].flag;
1641 dv.totweight = me->dvert[index].totweight;
1644 change = get_mp_change(wp->wpaint_prev+index, wpi->defbase_sel, neww - oldw);
1647 i = get_first_selected_nonzero_weight(&me->dvert[index], wpi->defbase_sel);
1649 tdw = &(me->dvert[index].dw[i]);
1650 tuw = defvert_verify_index(wp->wpaint_prev+index, tdw->def_nr);
1656 if(change && tuw->weight && tuw->weight * change) {
1657 if(tdw->weight != tuw->weight) {
1658 oldChange = tdw->weight/tuw->weight;
1659 testw = tuw->weight*change;
1660 if( testw > tuw->weight ) {
1661 if(change > oldChange) {
1662 /* reset the weights and use the new change */
1663 reset_to_prev(wp->wpaint_prev+index, &me->dvert[index]);
1666 /* the old change was more significant, so set
1667 * the change to 0 so that it will not do another multi-paint */
1672 if(change < oldChange) {
1673 reset_to_prev(wp->wpaint_prev+index, &me->dvert[index]);
1687 if(apply_mp_locks_normalize(me, wpi, index, dw, tdw, change, oldChange, oldw, neww)) {
1688 reset_to_prev(&dv, &me->dvert[index]);
1695 /* dvert may have been altered greatly */
1696 dw = defvert_find_index(&me->dvert[index], vgroup);
1698 if(me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */
1699 int j= mesh_get_x_mirror_vert(ob, index);
1701 /* copy, not paint again */
1702 uw= defvert_verify_index(me->dvert+j, (wpi->vgroup_mirror != -1) ? wpi->vgroup_mirror : vgroup);
1704 //uw->weight= dw->weight;
1706 apply_mp_locks_normalize(me, wpi, j, uw, tdw, change, oldChange, oldw, neww);
1713 /* *************** set wpaint operator ****************** */
1715 static int set_wpaint(bContext *C, wmOperator *UNUSED(op)) /* toggle */
1717 Object *ob= CTX_data_active_object(C);
1718 Scene *scene= CTX_data_scene(C);
1719 VPaint *wp= scene->toolsettings->wpaint;
1723 if(ob->id.lib || me==NULL) return OPERATOR_PASS_THROUGH;
1725 if(ob->mode & OB_MODE_WEIGHT_PAINT) ob->mode &= ~OB_MODE_WEIGHT_PAINT;
1726 else ob->mode |= OB_MODE_WEIGHT_PAINT;
1729 /* Weightpaint works by overriding colors in mesh,
1730 * so need to make sure we recalc on enter and
1731 * exit (exit needs doing regardless because we
1734 DAG_id_tag_update(&me->id, 0);
1736 if(ob->mode & OB_MODE_WEIGHT_PAINT) {
1740 wp= scene->toolsettings->wpaint= new_vpaint(1);
1742 paint_init(&wp->paint, PAINT_CURSOR_WEIGHT_PAINT);
1743 paint_cursor_start(C, weight_paint_poll);
1745 mesh_octree_table(ob, NULL, NULL, 's');
1747 /* verify if active weight group is also active bone */
1748 par= modifiers_isDeformedByArmature(ob);
1749 if(par && (par->mode & OB_MODE_POSE)) {
1750 bArmature *arm= par->data;
1753 ED_vgroup_select_by_name(ob, arm->act_bone->name);
1757 mesh_octree_table(NULL, NULL, NULL, 'e');
1758 mesh_mirrtopo_table(NULL, 'e');
1761 WM_event_add_notifier(C, NC_SCENE|ND_MODE, scene);
1763 return OPERATOR_FINISHED;
1766 /* for switching to/from mode */
1767 static int paint_poll_test(bContext *C)
1769 if(CTX_data_edit_object(C))
1771 if(CTX_data_active_object(C)==NULL)
1776 void PAINT_OT_weight_paint_toggle(wmOperatorType *ot)
1780 ot->name= "Weight Paint Mode";
1781 ot->idname= "PAINT_OT_weight_paint_toggle";
1784 ot->exec= set_wpaint;
1785 ot->poll= paint_poll_test;
1788 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1792 /* ************ weight paint operator ********** */
1798 float *vertexcosnos;
1801 /*variables for auto normalize*/
1803 char *vgroup_validmap; /*stores if vgroups tie to deforming bones or not*/
1808 static char *wpaint_make_validmap(Object *ob)
1812 char *vgroup_validmap;
1813 GHash *gh = BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "wpaint_make_validmap gh");
1816 /*add all names to a hash table*/
1817 for (dg=ob->defbase.first, i=0; dg; dg=dg->next, i++) {
1818 BLI_ghash_insert(gh, dg->name, NULL);
1824 vgroup_validmap= MEM_callocN(i, "wpaint valid map");
1826 /*now loop through the armature modifiers and identify deform bones*/
1827 for (md = ob->modifiers.first; md; md= !md->next && step1 ? (step1=0), modifiers_getVirtualModifierList(ob) : md->next) {
1828 if (!(md->mode & (eModifierMode_Realtime|eModifierMode_Virtual)))
1831 if (md->type == eModifierType_Armature)
1833 ArmatureModifierData *amd= (ArmatureModifierData*) md;
1835 if(amd->object && amd->object->pose) {
1836 bPose *pose= amd->object->pose;
1839 for (chan=pose->chanbase.first; chan; chan=chan->next) {
1840 if (chan->bone->flag & BONE_NO_DEFORM)
1843 if (BLI_ghash_haskey(gh, chan->name)) {
1844 BLI_ghash_remove(gh, chan->name, NULL, NULL);
1845 BLI_ghash_insert(gh, chan->name, SET_INT_IN_POINTER(1));
1852 /*add all names to a hash table*/
1853 for (dg=ob->defbase.first, i=0; dg; dg=dg->next, i++) {
1854 if (BLI_ghash_lookup(gh, dg->name) != NULL) {
1855 vgroup_validmap[i] = TRUE;
1859 BLI_ghash_free(gh, NULL, NULL);
1861 return vgroup_validmap;
1864 static int wpaint_stroke_test_start(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1866 Scene *scene= CTX_data_scene(C);
1867 struct PaintStroke *stroke = op->customdata;
1868 ToolSettings *ts= CTX_data_tool_settings(C);
1869 VPaint *wp= ts->wpaint;
1870 Object *ob= CTX_data_active_object(C);
1871 struct WPaintData *wpd;
1873 float mat[4][4], imat[4][4];
1875 if(scene->obedit) return OPERATOR_CANCELLED;
1878 if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH;
1880 /* if nothing was added yet, we make dverts and a vertex deform group */
1882 ED_vgroup_data_create(&me->id);
1883 WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
1886 /* make mode data storage */
1887 wpd= MEM_callocN(sizeof(struct WPaintData), "WPaintData");
1888 paint_stroke_set_mode_data(stroke, wpd);
1889 view3d_set_viewcontext(C, &wpd->vc);
1890 wpd->vgroup_mirror= -1;
1892 /*set up auto-normalize, and generate map for detecting which
1893 vgroups affect deform bones*/
1894 wpd->auto_normalize = ts->auto_normalize;
1895 wpd->defbase_tot = BLI_countlist(&ob->defbase);
1896 wpd->lock_flags = gen_lock_flags(ob, wpd->defbase_tot);
1897 if (wpd->auto_normalize || ts->multipaint || wpd->lock_flags)
1898 wpd->vgroup_validmap = wpaint_make_validmap(ob);
1900 // if(qual & LR_CTRLKEY) {
1901 // sample_wpaint(scene, ar, v3d, 0);
1904 // if(qual & LR_SHIFTKEY) {
1905 // sample_wpaint(scene, ar, v3d, 1);
1909 /* ALLOCATIONS! no return after this line */
1910 /* painting on subsurfs should give correct points too, this returns me->totvert amount */
1911 wpd->vertexcosnos= mesh_get_mapped_verts_nors(scene, ob);
1912 wpd->indexar= get_indexarray(me);
1913 copy_wpaint_prev(wp, me->dvert, me->totvert);
1915 /* this happens on a Bone select, when no vgroup existed yet */
1918 if((modob = modifiers_isDeformedByArmature(ob))) {
1919 Bone *actbone= ((bArmature *)modob->data)->act_bone;
1921 bPoseChannel *pchan= get_pose_channel(modob->pose, actbone->name);
1924 bDeformGroup *dg= defgroup_find_name(ob, pchan->name);
1926 dg= ED_vgroup_add_name(ob, pchan->name); /* sets actdef */
1928 ob->actdef= 1 + defgroup_find_index(ob, dg);
1933 if(ob->defbase.first==NULL) {
1937 // if(ob->lay & v3d->lay); else error("Active object is not in this layer");
1939 /* imat for normals */
1940 mul_m4_m4m4(mat, ob->obmat, wpd->vc.rv3d->viewmat);
1941 invert_m4_m4(imat, mat);
1942 copy_m3_m4(wpd->wpimat, imat);
1944 /* if mirror painting, find the other group */
1945 if(me->editflag & ME_EDIT_MIRROR_X) {
1946 wpaint_mirror_vgroup_ensure(ob, &wpd->vgroup_mirror);
1952 static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
1954 ToolSettings *ts= CTX_data_tool_settings(C);
1955 VPaint *wp= ts->wpaint;
1956 Brush *brush = paint_brush(&wp->paint);
1957 struct WPaintData *wpd= paint_stroke_mode_data(stroke);
1965 unsigned int index, totindex;
1967 float mval[2], pressure;
1970 /* intentionally dont initialize as NULL, make sure we initialize all members below */
1971 WeightPaintInfo wpi;
1973 /* cannot paint if there is no stroke data */
1975 /* XXX: force a redraw here, since even though we can't paint,
1976 * at least view won't freeze until stroke ends */
1977 ED_region_tag_redraw(CTX_wm_region(C));
1984 indexar= wpd->indexar;
1986 view3d_operator_needs_opengl(C);
1988 /* load projection matrix */
1989 mul_m4_m4m4(mat, ob->obmat, vc->rv3d->persmat);
1991 pressure = RNA_float_get(itemptr, "pressure");
1992 RNA_float_get_array(itemptr, "mouse", mval);
1993 mval[0]-= vc->ar->winrct.xmin;
1994 mval[1]-= vc->ar->winrct.ymin;
1998 /* *** setup WeightPaintInfo - pass onto do_weight_paint_vertex *** */
1999 wpi.defbase_tot= wpd->defbase_tot;
2000 wpi.defbase_sel= MEM_mallocN(wpi.defbase_tot*sizeof(char), "wpi.defbase_sel");
2001 wpi.defbase_tot_sel= get_selected_defgroups(ob, wpi.defbase_sel, wpi.defbase_tot);
2002 if(wpi.defbase_tot_sel == 0 && ob->actdef) wpi.defbase_tot_sel = 1;
2003 wpi.defbase_tot_unsel= wpi.defbase_tot - wpi.defbase_tot_sel;
2004 wpi.vgroup_mirror= wpd->vgroup_mirror;
2005 wpi.lock_flags= wpd->lock_flags;
2006 wpi.vgroup_validmap= wpd->vgroup_validmap;
2007 wpi.do_flip= RNA_boolean_get(itemptr, "pen_flip");
2008 wpi.do_multipaint= (ts->multipaint != 0);
2009 wpi.do_auto_normalize= (ts->auto_normalize != 0);
2010 /* *** done setting up WeightPaintInfo *** */
2014 swap_m4m4(wpd->vc.rv3d->persmat, mat);
2016 use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
2018 /* which faces are involved */
2019 if(wp->flag & VP_AREA) {
2020 /* Ugly hack, to avoid drawing vertex index when getting the face index buffer - campbell */
2021 me->editflag &= ~ME_EDIT_VERT_SEL;
2022 totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush_size(brush));
2023 me->editflag |= use_vert_sel ? ME_EDIT_VERT_SEL : 0;
2026 indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]);
2027 if(indexar[0]) totindex= 1;
2031 if(wp->flag & VP_COLINDEX) {
2032 for(index=0; index<totindex; index++) {
2033 if(indexar[index] && indexar[index]<=me->totface) {
2034 MFace *mface= ((MFace *)me->mface) + (indexar[index]-1);
2036 if(mface->mat_nr!=ob->actcol-1) {
2043 if((me->editflag & ME_EDIT_PAINT_MASK) && me->mface) {
2044 for(index=0; index<totindex; index++) {
2045 if(indexar[index] && indexar[index]<=me->totface) {
2046 MFace *mface= ((MFace *)me->mface) + (indexar[index]-1);
2048 if((mface->flag & ME_FACE_SEL)==0) {
2055 /* make sure each vertex gets treated only once */
2056 /* and calculate filter weight */
2058 if(brush->vertexpaint_tool==VP_BLUR)
2061 paintweight= ts->vgroup_weight;
2063 for(index=0; index<totindex; index++) {
2064 if(indexar[index] && indexar[index]<=me->totface) {
2065 MFace *mface= me->mface + (indexar[index]-1);
2068 me->dvert[mface->v1].flag = (me->mvert[mface->v1].flag & SELECT);
2069 me->dvert[mface->v2].flag = (me->mvert[mface->v2].flag & SELECT);
2070 me->dvert[mface->v3].flag = (me->mvert[mface->v3].flag & SELECT);
2071 if(mface->v4) me->dvert[mface->v4].flag = (me->mvert[mface->v4].flag & SELECT);
2074 me->dvert[mface->v1].flag= 1;
2075 me->dvert[mface->v2].flag= 1;
2076 me->dvert[mface->v3].flag= 1;
2077 if(mface->v4) me->dvert[mface->v4].flag= 1;
2080 if(brush->vertexpaint_tool==VP_BLUR) {
2081 MDeformWeight *dw, *(*dw_func)(MDeformVert *, const int);
2082 unsigned int fidx= mface->v4 ? 3:2;
2084 if(wp->flag & VP_ONLYVGROUP)
2085 dw_func= (MDeformWeight *(*)(MDeformVert *, const int))defvert_find_index;
2087 dw_func= defvert_verify_index;
2090 unsigned int vidx= *(&mface->v1 + fidx);
2092 dw= dw_func(me->dvert+vidx, ob->actdef-1);
2094 paintweight+= dw->weight;
2104 if(brush->vertexpaint_tool==VP_BLUR)
2105 paintweight/= (float)totw;
2107 for(index=0; index<totindex; index++) {
2109 if(indexar[index] && indexar[index]<=me->totface) {
2110 MFace *mf= me->mface + (indexar[index]-1);
2111 unsigned int fidx= mf->v4 ? 3:2;;
2113 unsigned int vidx= *(&mf->v1 + fidx);
2115 if(me->dvert[vidx].flag) {
2116 alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*vidx, mval, pressure);
2118 do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight);
2120 me->dvert[vidx].flag= 0;
2127 /* *** free wpi members */
2128 MEM_freeN(wpi.defbase_sel);
2129 /* *** dont freeing wpi members */
2132 swap_m4m4(vc->rv3d->persmat, mat);
2134 DAG_id_tag_update(ob->data, 0);
2135 ED_region_tag_redraw(vc->ar);
2138 static void wpaint_stroke_done(bContext *C, struct PaintStroke *stroke)
2140 ToolSettings *ts= CTX_data_tool_settings(C);
2141 Object *ob= CTX_data_active_object(C);
2142 struct WPaintData *wpd= paint_stroke_mode_data(stroke);
2145 if(wpd->vertexcosnos)
2146 MEM_freeN(wpd->vertexcosnos);
2147 MEM_freeN(wpd->indexar);
2149 if (wpd->vgroup_validmap)
2150 MEM_freeN(wpd->vgroup_validmap);
2152 MEM_freeN(wpd->lock_flags);
2157 /* frees prev buffer */
2158 copy_wpaint_prev(ts->wpaint, NULL, 0);
2160 /* and particles too */
2161 if(ob->particlesystem.first) {
2162 ParticleSystem *psys;
2165 for(psys= ob->particlesystem.first; psys; psys= psys->next) {
2166 for(i=0; i<PSYS_TOT_VG; i++) {
2167 if(psys->vgroup[i]==ob->actdef) {
2168 psys->recalc |= PSYS_RECALC_RESET;
2175 DAG_id_tag_update(ob->data, 0);
2179 static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
2182 op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start,
2183 wpaint_stroke_update_step,
2184 wpaint_stroke_done, event->type);
2186 /* add modal handler */
2187 WM_event_add_modal_handler(C, op);
2189 op->type->modal(C, op, event);
2191 return OPERATOR_RUNNING_MODAL;
2194 static int wpaint_cancel(bContext *C, wmOperator *op)
2196 paint_stroke_cancel(C, op);
2198 return OPERATOR_CANCELLED;
2201 void PAINT_OT_weight_paint(wmOperatorType *ot)
2205 ot->name= "Weight Paint";
2206 ot->idname= "PAINT_OT_weight_paint";
2209 ot->invoke= wpaint_invoke;
2210 ot->modal= paint_stroke_modal;
2211 /* ot->exec= vpaint_exec; <-- needs stroke property */
2212 ot->poll= weight_paint_poll;
2213 ot->cancel= wpaint_cancel;
2216 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
2218 RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
2221 static int weight_paint_set_exec(bContext *C, wmOperator *UNUSED(op))
2223 struct Scene *scene= CTX_data_scene(C);
2224 Object *obact = CTX_data_active_object(C);
2226 wpaint_fill(scene->toolsettings->wpaint, obact, scene->toolsettings->vgroup_weight);
2227 ED_region_tag_redraw(CTX_wm_region(C)); /* XXX - should redraw all 3D views */
2228 return OPERATOR_FINISHED;
2231 void PAINT_OT_weight_set(wmOperatorType *ot)
2234 ot->name= "Set Weight";
2235 ot->idname= "PAINT_OT_weight_set";
2238 ot->exec= weight_paint_set_exec;
2239 ot->poll= mask_paint_poll; /* it was facemask_paint_poll */
2242 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2245 /* ************ set / clear vertex paint mode ********** */
2248 static int set_vpaint(bContext *C, wmOperator *op) /* toggle */
2250 Object *ob= CTX_data_active_object(C);
2251 Scene *scene= CTX_data_scene(C);
2252 VPaint *vp= scene->toolsettings->vpaint;
2257 if(me==NULL || object_data_is_libdata(ob)) {
2258 ob->mode &= ~OB_MODE_VERTEX_PAINT;
2259 return OPERATOR_PASS_THROUGH;
2262 if(me && me->mcol==NULL) make_vertexcol(ob);
2264 /* toggle: end vpaint */
2265 if(ob->mode & OB_MODE_VERTEX_PAINT) {
2267 ob->mode &= ~OB_MODE_VERTEX_PAINT;
2270 ob->mode |= OB_MODE_VERTEX_PAINT;
2271 /* Turn off weight painting */
2272 if (ob->mode & OB_MODE_WEIGHT_PAINT)
2276 vp= scene->toolsettings->vpaint= new_vpaint(0);
2278 paint_cursor_start(C, vertex_paint_poll);
2280 paint_init(&vp->paint, PAINT_CURSOR_VERTEX_PAINT);
2284 /* update modifier stack for mapping requirements */
2285 DAG_id_tag_update(&me->id, 0);
2287 WM_event_add_notifier(C, NC_SCENE|ND_MODE, scene);
2289 return OPERATOR_FINISHED;
2292 void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
2296 ot->name= "Vertex Paint Mode";
2297 ot->idname= "PAINT_OT_vertex_paint_toggle";
2300 ot->exec= set_vpaint;
2301 ot->poll= paint_poll_test;
2304 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2309 /* ********************** vertex paint operator ******************* */
2311 /* Implementation notes:
2314 - validate context (add mcol)
2315 - create customdata storage
2316 - call paint once (mouse click)
2320 - for every mousemove, apply vertex paint
2321 - exit on mouse release, free customdata
2322 (return OPERATOR_FINISHED also removes handler and operator)
2325 - implement a stroke event (or mousemove with past positons)
2326 - revise whether op->customdata should be added in object, in set_vpaint
2330 typedef struct VPaintData {
2332 unsigned int paintcol;
2334 float *vertexcosnos;
2338 static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *UNUSED(event))
2340 ToolSettings *ts= CTX_data_tool_settings(C);
2341 struct PaintStroke *stroke = op->customdata;
2342 VPaint *vp= ts->vpaint;
2343 struct VPaintData *vpd;
2344 Object *ob= CTX_data_active_object(C);
2346 float mat[4][4], imat[4][4];
2348 /* context checks could be a poll() */
2350 if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH;
2352 if(me->mcol==NULL) make_vertexcol(ob);
2353 if(me->mcol==NULL) return OPERATOR_CANCELLED;
2355 /* make mode data storage */
2356 vpd= MEM_callocN(sizeof(struct VPaintData), "VPaintData");
2357 paint_stroke_set_mode_data(stroke, vpd);
2358 view3d_set_viewcontext(C, &vpd->vc);
2360 vpd->vertexcosnos= mesh_get_mapped_verts_nors(vpd->vc.scene, ob);
2361 vpd->indexar= get_indexarray(me);
2362 vpd->paintcol= vpaint_get_current_col(vp);
2365 copy_vpaint_prev(vp, (unsigned int *)me->mcol, me->totface);
2367 /* some old cruft to sort out later */
2368 mul_m4_m4m4(mat, ob->obmat, vpd->vc.rv3d->viewmat);
2369 invert_m4_m4(imat, mat);
2370 copy_m3_m4(vpd->vpimat, imat);
2375 static void vpaint_paint_face(VPaint *vp, VPaintData *vpd, Object *ob, const unsigned int index, const float mval[2], float pressure, int UNUSED(flip))
2377 ViewContext *vc = &vpd->vc;
2378 Brush *brush = paint_brush(&vp->paint);
2379 Mesh *me = get_mesh(ob);
2380 MFace *mface= &me->mface[index];
2381 unsigned int *mcol= ((unsigned int*)me->mcol) + 4*index;
2382 unsigned int *mcolorig= ((unsigned int*)vp->vpaint_prev) + 4*index;
2386 if((vp->flag & VP_COLINDEX && mface->mat_nr!=ob->actcol-1) ||
2387 ((me->editflag & ME_EDIT_PAINT_MASK) && !(mface->flag & ME_FACE_SEL)))
2390 if(brush->vertexpaint_tool==VP_BLUR) {
2391 unsigned int fcol1= mcol_blend( mcol[0], mcol[1], 128);
2393 unsigned int fcol2= mcol_blend( mcol[2], mcol[3], 128);
2394 vpd->paintcol= mcol_blend( fcol1, fcol2, 128);
2397 vpd->paintcol= mcol_blend( mcol[2], fcol1, 170);
2402 for(i = 0; i < (mface->v4 ? 4 : 3); ++i) {
2403 alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*(&mface->v1)[i], mval, pressure);
2405 vpaint_blend(vp, mcol+i, mcolorig+i, vpd->paintcol, (int)(alpha*255.0f));
2409 static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
2411 ToolSettings *ts= CTX_data_tool_settings(C);
2412 struct VPaintData *vpd = paint_stroke_mode_data(stroke);
2413 VPaint *vp= ts->vpaint;
2414 Brush *brush = paint_brush(&vp->paint);
2415 ViewContext *vc= &vpd->vc;
2416 Object *ob= vc->obact;
2419 int *indexar= vpd->indexar;
2420 int totindex, index, flip;
2421 float pressure, mval[2];
2423 RNA_float_get_array(itemptr, "mouse", mval);
2424 flip = RNA_boolean_get(itemptr, "pen_flip");
2425 pressure = RNA_float_get(itemptr, "pressure");
2427 view3d_operator_needs_opengl(C);
2429 /* load projection matrix */
2430 mul_m4_m4m4(mat, ob->obmat, vc->rv3d->persmat);
2432 mval[0]-= vc->ar->winrct.xmin;
2433 mval[1]-= vc->ar->winrct.ymin;
2436 /* which faces are involved */
2437 if(vp->flag & VP_AREA) {
2438 totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush_size(brush));
2441 indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]);
2442 if(indexar[0]) totindex= 1;
2446 swap_m4m4(vc->rv3d->persmat, mat);
2448 for(index=0; index<totindex; index++) {
2449 if(indexar[index] && indexar[index]<=me->totface)
2450 vpaint_paint_face(vp, vpd, ob, indexar[index]-1, mval, pressure, flip);
2453 swap_m4m4(vc->rv3d->persmat, mat);
2455 /* was disabled because it is slow, but necessary for blur */
2456 if(brush->vertexpaint_tool == VP_BLUR)
2457 do_shared_vertexcol(me);
2459 ED_region_tag_redraw(vc->ar);
2461 DAG_id_tag_update(ob->data, 0);
2464 static void vpaint_stroke_done(bContext *C, struct PaintStroke *stroke)
2466 ToolSettings *ts= CTX_data_tool_settings(C);
2467 struct VPaintData *vpd= paint_stroke_mode_data(stroke);
2469 if(vpd->vertexcosnos)
2470 MEM_freeN(vpd->vertexcosnos);
2471 MEM_freeN(vpd->indexar);
2473 /* frees prev buffer */
2474 copy_vpaint_prev(ts->vpaint, NULL, 0);
2479 static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
2482 op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start,
2483 vpaint_stroke_update_step,
2484 vpaint_stroke_done, event->type);
2486 /* add modal handler */
2487 WM_event_add_modal_handler(C, op);
2489 op->type->modal(C, op, event);
2491 return OPERATOR_RUNNING_MODAL;
2494 static int vpaint_cancel(bContext *C, wmOperator *op)
2496 paint_stroke_cancel(C, op);
2498 return OPERATOR_CANCELLED;
2501 void PAINT_OT_vertex_paint(wmOperatorType *ot)
2504 ot->name= "Vertex Paint";
2505 ot->idname= "PAINT_OT_vertex_paint";
2508 ot->invoke= vpaint_invoke;
2509 ot->modal= paint_stroke_modal;
2510 /* ot->exec= vpaint_exec; <-- needs stroke property */
2511 ot->poll= vertex_paint_poll;
2512 ot->cancel= vpaint_cancel;
2515 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
2517 RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
2520 /* ********************** weight from bones operator ******************* */
2522 static int weight_from_bones_poll(bContext *C)
2524 Object *ob= CTX_data_active_object(C);
2526 return (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && modifiers_isDeformedByArmature(ob));
2529 static int weight_from_bones_exec(bContext *C, wmOperator *op)
2531 Scene *scene= CTX_data_scene(C);
2532 Object *ob= CTX_data_active_object(C);
2533 Object *armob= modifiers_isDeformedByArmature(ob);
2535 int type= RNA_enum_get(op->ptr, "type");
2537 create_vgroups_from_armature(op->reports, scene, ob, armob, type, (me->editflag & ME_EDIT_MIRROR_X));
2539 DAG_id_tag_update(&me->id, 0);
2540 WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
2542 return OPERATOR_FINISHED;
2545 void PAINT_OT_weight_from_bones(wmOperatorType *ot)
2547 static EnumPropertyItem type_items[]= {
2548 {ARM_GROUPS_AUTO, "AUTOMATIC", 0, "Automatic", "Automatic weights froms bones"},
2549 {ARM_GROUPS_ENVELOPE, "ENVELOPES", 0, "From Envelopes", "Weights from envelopes with user defined radius"},
2550 {0, NULL, 0, NULL, NULL}};
2553 ot->name= "Weight from Bones";
2554 ot->idname= "PAINT_OT_weight_from_bones";
2557 ot->exec= weight_from_bones_exec;
2558 ot->invoke= WM_menu_invoke;
2559 ot->poll= weight_from_bones_poll;
2562 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2565 ot->prop= RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights");