add the property as an argument to enum item functions, not used yet but needed for...
[blender.git] / source / blender / editors / sculpt_paint / paint_vertex.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
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.
10  *
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.
15  *
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.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 /** \file blender/editors/sculpt_paint/paint_vertex.c
31  *  \ingroup edsculpt
32  */
33
34
35 #include <math.h>
36 #include <string.h>
37
38 #ifdef WIN32
39 #include <io.h>
40 #else
41 #include <unistd.h>
42 #endif   
43
44 #include "MEM_guardedalloc.h"
45
46 #include "BLI_blenlib.h"
47 #include "BLI_math.h"
48 #include "BLI_utildefines.h"
49 #include "BLI_ghash.h"
50
51 #include "IMB_imbuf.h"
52 #include "IMB_imbuf_types.h"
53
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"
61
62 #include "RNA_access.h"
63 #include "RNA_define.h"
64 #include "RNA_enum_types.h"
65
66 #include "BKE_DerivedMesh.h"
67 #include "BKE_action.h"
68 #include "BKE_brush.h"
69 #include "BKE_context.h"
70 #include "BKE_depsgraph.h"
71 #include "BKE_deform.h"
72 #include "BKE_mesh.h"
73 #include "BKE_modifier.h"
74 #include "BKE_object.h"
75 #include "BKE_paint.h"
76 #include "BKE_report.h"
77
78 #include "WM_api.h"
79 #include "WM_types.h"
80
81
82 #include "ED_armature.h"
83 #include "ED_mesh.h"
84 #include "ED_screen.h"
85 #include "ED_view3d.h"
86
87 #include "paint_intern.h"
88
89 /* brush->vertexpaint_tool */
90 #define VP_MIX  0
91 #define VP_ADD  1
92 #define VP_SUB  2
93 #define VP_MUL  3
94 #define VP_BLUR 4
95 #define VP_LIGHTEN      5
96 #define VP_DARKEN       6
97
98 /* polling - retrieve whether cursor should be set or operator should be done */
99
100
101 /* Returns true if vertex paint mode is active */
102 int vertex_paint_mode_poll(bContext *C)
103 {
104         Object *ob = CTX_data_active_object(C);
105
106         return ob && ob->mode == OB_MODE_VERTEX_PAINT && ((Mesh *)ob->data)->totface;
107 }
108
109 int vertex_paint_poll(bContext *C)
110 {
111         if(vertex_paint_mode_poll(C) && 
112            paint_brush(&CTX_data_tool_settings(C)->vpaint->paint)) {
113                 ScrArea *sa= CTX_wm_area(C);
114                 if(sa->spacetype==SPACE_VIEW3D) {
115                         ARegion *ar= CTX_wm_region(C);
116                         if(ar->regiontype==RGN_TYPE_WINDOW)
117                                 return 1;
118                         }
119                 }
120         return 0;
121 }
122
123 int weight_paint_mode_poll(bContext *C)
124 {
125         Object *ob = CTX_data_active_object(C);
126
127         return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((Mesh *)ob->data)->totface;
128 }
129
130 int weight_paint_poll(bContext *C)
131 {
132         Object *ob= CTX_data_active_object(C);
133         ScrArea *sa;
134
135         if(     (ob != NULL) &&
136                 (ob->mode & OB_MODE_WEIGHT_PAINT) &&
137                 (paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != NULL) &&
138                 (sa= CTX_wm_area(C)) &&
139                 (sa->spacetype == SPACE_VIEW3D)
140         ) {
141                 ARegion *ar= CTX_wm_region(C);
142                 if(ar->regiontype==RGN_TYPE_WINDOW) {
143                         return 1;
144                 }
145         }
146         return 0;
147 }
148
149 static VPaint *new_vpaint(int wpaint)
150 {
151         VPaint *vp= MEM_callocN(sizeof(VPaint), "VPaint");
152         
153         vp->flag= VP_AREA+VP_SPRAY;
154         
155         if(wpaint)
156                 vp->flag= VP_AREA;
157
158         return vp;
159 }
160
161 static int *get_indexarray(Mesh *me)
162 {
163         return MEM_mallocN(sizeof(int)*(me->totface+1), "vertexpaint");
164 }
165
166
167 /* in contradiction to cpack drawing colors, the MCOL colors (vpaint colors) are per byte! 
168    so not endian sensitive. Mcol = ABGR!!! so be cautious with cpack calls */
169
170 static unsigned int rgba_to_mcol(float r, float g, float b, float a)
171 {
172         int ir, ig, ib, ia;
173         unsigned int col;
174         char *cp;
175         
176         ir= floor(255.0f * r);
177         if(ir<0) ir= 0; else if(ir>255) ir= 255;
178         ig= floor(255.0f * g);
179         if(ig<0) ig= 0; else if(ig>255) ig= 255;
180         ib= floor(255.0f * b);
181         if(ib<0) ib= 0; else if(ib>255) ib= 255;
182         ia= floor(255.0f * a);
183         if(ia<0) ia= 0; else if(ia>255) ia= 255;
184         
185         cp= (char *)&col;
186         cp[0]= ia;
187         cp[1]= ib;
188         cp[2]= ig;
189         cp[3]= ir;
190         
191         return col;
192         
193 }
194
195 unsigned int vpaint_get_current_col(VPaint *vp)
196 {
197         Brush *brush = paint_brush(&vp->paint);
198         return rgba_to_mcol(brush->rgb[0], brush->rgb[1], brush->rgb[2], 1.0f);
199 }
200
201 static void do_shared_vertexcol(Mesh *me)
202 {
203         /* if no mcol: do not do */
204         /* if tface: only the involved faces, otherwise all */
205         MFace *mface;
206         MTFace *tface;
207         int a;
208         short *scolmain, *scol;
209         char *mcol;
210         
211         if(me->mcol==NULL || me->totvert==0 || me->totface==0) return;
212         
213         scolmain= MEM_callocN(4*sizeof(short)*me->totvert, "colmain");
214         
215         tface= me->mtface;
216         mface= me->mface;
217         mcol= (char *)me->mcol;
218         for(a=me->totface; a>0; a--, mface++, mcol+=16) {
219                 if((tface && tface->mode & TF_SHAREDCOL) || (me->editflag & ME_EDIT_PAINT_MASK)==0) {
220                         scol= scolmain+4*mface->v1;
221                         scol[0]++; scol[1]+= mcol[1]; scol[2]+= mcol[2]; scol[3]+= mcol[3];
222                         scol= scolmain+4*mface->v2;
223                         scol[0]++; scol[1]+= mcol[5]; scol[2]+= mcol[6]; scol[3]+= mcol[7];
224                         scol= scolmain+4*mface->v3;
225                         scol[0]++; scol[1]+= mcol[9]; scol[2]+= mcol[10]; scol[3]+= mcol[11];
226                         if(mface->v4) {
227                                 scol= scolmain+4*mface->v4;
228                                 scol[0]++; scol[1]+= mcol[13]; scol[2]+= mcol[14]; scol[3]+= mcol[15];
229                         }
230                 }
231                 if(tface) tface++;
232         }
233         
234         a= me->totvert;
235         scol= scolmain;
236         while(a--) {
237                 if(scol[0]>1) {
238                         scol[1]/= scol[0];
239                         scol[2]/= scol[0];
240                         scol[3]/= scol[0];
241                 }
242                 scol+= 4;
243         }
244         
245         tface= me->mtface;
246         mface= me->mface;
247         mcol= (char *)me->mcol;
248         for(a=me->totface; a>0; a--, mface++, mcol+=16) {
249                 if((tface && tface->mode & TF_SHAREDCOL) || (me->editflag & ME_EDIT_PAINT_MASK)==0) {
250                         scol= scolmain+4*mface->v1;
251                         mcol[1]= scol[1]; mcol[2]= scol[2]; mcol[3]= scol[3];
252                         scol= scolmain+4*mface->v2;
253                         mcol[5]= scol[1]; mcol[6]= scol[2]; mcol[7]= scol[3];
254                         scol= scolmain+4*mface->v3;
255                         mcol[9]= scol[1]; mcol[10]= scol[2]; mcol[11]= scol[3];
256                         if(mface->v4) {
257                                 scol= scolmain+4*mface->v4;
258                                 mcol[13]= scol[1]; mcol[14]= scol[2]; mcol[15]= scol[3];
259                         }
260                 }
261                 if(tface) tface++;
262         }
263
264         MEM_freeN(scolmain);
265 }
266
267 static void make_vertexcol(Object *ob)  /* single ob */
268 {
269         Mesh *me;
270         if(!ob || ob->id.lib) return;
271         me= get_mesh(ob);
272         if(me==NULL) return;
273         if(me->edit_mesh) return;
274
275         /* copies from shadedisplist to mcol */
276         if(!me->mcol) {
277                 CustomData_add_layer(&me->fdata, CD_MCOL, CD_CALLOC, NULL, me->totface);
278                 mesh_update_customdata_pointers(me);
279         }
280
281         //if(shade)
282         //      shadeMeshMCol(scene, ob, me);
283         //else
284
285         memset(me->mcol, 255, 4*sizeof(MCol)*me->totface);
286         
287         DAG_id_tag_update(&me->id, 0);
288         
289 }
290
291 static void copy_vpaint_prev(VPaint *vp, unsigned int *mcol, int tot)
292 {
293         if(vp->vpaint_prev) {
294                 MEM_freeN(vp->vpaint_prev);
295                 vp->vpaint_prev= NULL;
296         }
297         vp->tot= tot;   
298         
299         if(mcol==NULL || tot==0) return;
300         
301         vp->vpaint_prev= MEM_mallocN(4*sizeof(int)*tot, "vpaint_prev");
302         memcpy(vp->vpaint_prev, mcol, 4*sizeof(int)*tot);
303         
304 }
305
306 static void copy_wpaint_prev (VPaint *wp, MDeformVert *dverts, int dcount)
307 {
308         if (wp->wpaint_prev) {
309                 free_dverts(wp->wpaint_prev, wp->tot);
310                 wp->wpaint_prev= NULL;
311         }
312         
313         if(dverts && dcount) {
314                 
315                 wp->wpaint_prev = MEM_mallocN (sizeof(MDeformVert)*dcount, "wpaint prev");
316                 wp->tot = dcount;
317                 copy_dverts (wp->wpaint_prev, dverts, dcount);
318         }
319 }
320
321
322 void vpaint_fill(Object *ob, unsigned int paintcol)
323 {
324         Mesh *me;
325         MFace *mf;
326         unsigned int *mcol;
327         int i, selected;
328
329         me= get_mesh(ob);
330         if(me==NULL || me->totface==0) return;
331
332         if(!me->mcol)
333                 make_vertexcol(ob);
334
335         selected= (me->editflag & ME_EDIT_PAINT_MASK);
336
337         mf = me->mface;
338         mcol = (unsigned int*)me->mcol;
339         for (i = 0; i < me->totface; i++, mf++, mcol+=4) {
340                 if (!selected || mf->flag & ME_FACE_SEL) {
341                         mcol[0] = paintcol;
342                         mcol[1] = paintcol;
343                         mcol[2] = paintcol;
344                         mcol[3] = paintcol;
345                 }
346         }
347         
348         DAG_id_tag_update(&me->id, 0);
349 }
350
351
352 /* fills in the selected faces with the current weight and vertex group */
353 void wpaint_fill(VPaint *wp, Object *ob, float paintweight)
354 {
355         Mesh *me;
356         MFace *mface;
357         MDeformWeight *dw, *uw;
358         int *indexar;
359         int index, vgroup;
360         unsigned int faceverts[5]={0,0,0,0,0};
361         unsigned char i;
362         int vgroup_mirror= -1;
363         int selected;
364         
365         me= ob->data;
366         if(me==NULL || me->totface==0 || me->dvert==NULL || !me->mface) return;
367         
368         selected= (me->editflag & ME_EDIT_PAINT_MASK);
369
370         indexar= get_indexarray(me);
371
372         if(selected) {
373                 for(index=0, mface=me->mface; index<me->totface; index++, mface++) {
374                         if((mface->flag & ME_FACE_SEL)==0)
375                                 indexar[index]= 0;
376                         else
377                                 indexar[index]= index+1;
378                 }
379         }
380         else {
381                 for(index=0; index<me->totface; index++)
382                         indexar[index]= index+1;
383         }
384         
385         vgroup= ob->actdef-1;
386         
387         /* directly copied from weight_paint, should probaby split into a separate function */
388         /* if mirror painting, find the other group */          
389         if(me->editflag & ME_EDIT_MIRROR_X) {
390                 bDeformGroup *defgroup= BLI_findlink(&ob->defbase, ob->actdef-1);
391                 if(defgroup) {
392                         bDeformGroup *curdef;
393                         int actdef= 0;
394                         char name[32];
395
396                         flip_side_name(name, defgroup->name, FALSE);
397
398                         for (curdef = ob->defbase.first; curdef; curdef=curdef->next, actdef++)
399                                 if (!strcmp(curdef->name, name))
400                                         break;
401                         if(curdef==NULL) {
402                                 int olddef= ob->actdef; /* tsk, ED_vgroup_add sets the active defgroup */
403                                 curdef= ED_vgroup_add_name (ob, name);
404                                 ob->actdef= olddef;
405                         }
406                         
407                         if(curdef && curdef!=defgroup)
408                                 vgroup_mirror= actdef;
409                 }
410         }
411         /* end copy from weight_paint*/
412         
413         copy_wpaint_prev(wp, me->dvert, me->totvert);
414         
415         for(index=0; index<me->totface; index++) {
416                 if(indexar[index] && indexar[index]<=me->totface) {
417                         mface= me->mface + (indexar[index]-1);
418                         /* just so we can loop through the verts */
419                         faceverts[0]= mface->v1;
420                         faceverts[1]= mface->v2;
421                         faceverts[2]= mface->v3;
422                         faceverts[3]= mface->v4;
423                         for (i=0; i<3 || faceverts[i]; i++) {
424                                 if(!((me->dvert+faceverts[i])->flag)) {
425                                         dw= defvert_verify_index(me->dvert+faceverts[i], vgroup);
426                                         if(dw) {
427                                                 uw= defvert_verify_index(wp->wpaint_prev+faceverts[i], vgroup);
428                                                 uw->weight= dw->weight; /* set the undo weight */
429                                                 dw->weight= paintweight;
430                                                 
431                                                 if(me->editflag & ME_EDIT_MIRROR_X) {   /* x mirror painting */
432                                                         int j= mesh_get_x_mirror_vert(ob, faceverts[i]);
433                                                         if(j>=0) {
434                                                                 /* copy, not paint again */
435                                                                 if(vgroup_mirror != -1) {
436                                                                         dw= defvert_verify_index(me->dvert+j, vgroup_mirror);
437                                                                         uw= defvert_verify_index(wp->wpaint_prev+j, vgroup_mirror);
438                                                                 } else {
439                                                                         dw= defvert_verify_index(me->dvert+j, vgroup);
440                                                                         uw= defvert_verify_index(wp->wpaint_prev+j, vgroup);
441                                                                 }
442                                                                 uw->weight= dw->weight; /* set the undo weight */
443                                                                 dw->weight= paintweight;
444                                                         }
445                                                 }
446                                         }
447                                         (me->dvert+faceverts[i])->flag= 1;
448                                 }
449                         }
450                 }
451         }
452         
453         index=0;
454         while (index<me->totvert) {
455                 (me->dvert+index)->flag= 0;
456                 index++;
457         }
458         
459         MEM_freeN(indexar);
460         copy_wpaint_prev(wp, NULL, 0);
461
462         DAG_id_tag_update(&me->id, 0);
463 }
464
465 /* XXX: should be re-implemented as a vertex/weight paint 'color correct' operator
466  
467 void vpaint_dogamma(Scene *scene)
468 {
469         VPaint *vp= scene->toolsettings->vpaint;
470         Mesh *me;
471         Object *ob;
472         float igam, fac;
473         int a, temp;
474         unsigned char *cp, gamtab[256];
475
476         ob= OBACT;
477         me= get_mesh(ob);
478
479         if(!(ob->mode & OB_MODE_VERTEX_PAINT)) return;
480         if(me==0 || me->mcol==0 || me->totface==0) return;
481
482         igam= 1.0/vp->gamma;
483         for(a=0; a<256; a++) {
484                 
485                 fac= ((float)a)/255.0;
486                 fac= vp->mul*pow( fac, igam);
487                 
488                 temp= 255.9*fac;
489                 
490                 if(temp<=0) gamtab[a]= 0;
491                 else if(temp>=255) gamtab[a]= 255;
492                 else gamtab[a]= temp;
493         }
494
495         a= 4*me->totface;
496         cp= (unsigned char *)me->mcol;
497         while(a--) {
498                 
499                 cp[1]= gamtab[ cp[1] ];
500                 cp[2]= gamtab[ cp[2] ];
501                 cp[3]= gamtab[ cp[3] ];
502                 
503                 cp+= 4;
504         }
505 }
506  */
507
508 static unsigned int mcol_blend(unsigned int col1, unsigned int col2, int fac)
509 {
510         char *cp1, *cp2, *cp;
511         int mfac;
512         unsigned int col=0;
513         
514         if(fac==0) return col1;
515         if(fac>=255) return col2;
516
517         mfac= 255-fac;
518         
519         cp1= (char *)&col1;
520         cp2= (char *)&col2;
521         cp=  (char *)&col;
522         
523         cp[0]= 255;
524         cp[1]= (mfac*cp1[1]+fac*cp2[1])/255;
525         cp[2]= (mfac*cp1[2]+fac*cp2[2])/255;
526         cp[3]= (mfac*cp1[3]+fac*cp2[3])/255;
527         
528         return col;
529 }
530
531 static unsigned int mcol_add(unsigned int col1, unsigned int col2, int fac)
532 {
533         char *cp1, *cp2, *cp;
534         int temp;
535         unsigned int col=0;
536         
537         if(fac==0) return col1;
538         
539         cp1= (char *)&col1;
540         cp2= (char *)&col2;
541         cp=  (char *)&col;
542         
543         cp[0]= 255;
544         temp= cp1[1] + ((fac*cp2[1])/255);
545         if(temp>254) cp[1]= 255; else cp[1]= temp;
546         temp= cp1[2] + ((fac*cp2[2])/255);
547         if(temp>254) cp[2]= 255; else cp[2]= temp;
548         temp= cp1[3] + ((fac*cp2[3])/255);
549         if(temp>254) cp[3]= 255; else cp[3]= temp;
550         
551         return col;
552 }
553
554 static unsigned int mcol_sub(unsigned int col1, unsigned int col2, int fac)
555 {
556         char *cp1, *cp2, *cp;
557         int temp;
558         unsigned int col=0;
559         
560         if(fac==0) return col1;
561         
562         cp1= (char *)&col1;
563         cp2= (char *)&col2;
564         cp=  (char *)&col;
565         
566         cp[0]= 255;
567         temp= cp1[1] - ((fac*cp2[1])/255);
568         if(temp<0) cp[1]= 0; else cp[1]= temp;
569         temp= cp1[2] - ((fac*cp2[2])/255);
570         if(temp<0) cp[2]= 0; else cp[2]= temp;
571         temp= cp1[3] - ((fac*cp2[3])/255);
572         if(temp<0) cp[3]= 0; else cp[3]= temp;
573         
574         return col;
575 }
576
577 static unsigned int mcol_mul(unsigned int col1, unsigned int col2, int fac)
578 {
579         char *cp1, *cp2, *cp;
580         int mfac;
581         unsigned int col=0;
582         
583         if(fac==0) return col1;
584
585         mfac= 255-fac;
586         
587         cp1= (char *)&col1;
588         cp2= (char *)&col2;
589         cp=  (char *)&col;
590         
591         /* first mul, then blend the fac */
592         cp[0]= 255;
593         cp[1]= (mfac*cp1[1] + fac*((cp2[1]*cp1[1])/255)  )/255;
594         cp[2]= (mfac*cp1[2] + fac*((cp2[2]*cp1[2])/255)  )/255;
595         cp[3]= (mfac*cp1[3] + fac*((cp2[3]*cp1[3])/255)  )/255;
596
597         
598         return col;
599 }
600
601 static unsigned int mcol_lighten(unsigned int col1, unsigned int col2, int fac)
602 {
603         char *cp1, *cp2, *cp;
604         int mfac;
605         unsigned int col=0;
606         
607         if(fac==0) return col1;
608         if(fac>=255) return col2;
609
610         mfac= 255-fac;
611         
612         cp1= (char *)&col1;
613         cp2= (char *)&col2;
614         cp=  (char *)&col;
615         
616         /* See if are lighter, if so mix, else dont do anything.
617         if the paint col is darker then the original, then ignore */
618         if (cp1[1]+cp1[2]+cp1[3] > cp2[1]+cp2[2]+cp2[3])
619                 return col1;
620         
621         cp[0]= 255;
622         cp[1]= (mfac*cp1[1]+fac*cp2[1])/255;
623         cp[2]= (mfac*cp1[2]+fac*cp2[2])/255;
624         cp[3]= (mfac*cp1[3]+fac*cp2[3])/255;
625         
626         return col;
627 }
628
629 static unsigned int mcol_darken(unsigned int col1, unsigned int col2, int fac)
630 {
631         char *cp1, *cp2, *cp;
632         int mfac;
633         unsigned int col=0;
634         
635         if(fac==0) return col1;
636         if(fac>=255) return col2;
637
638         mfac= 255-fac;
639         
640         cp1= (char *)&col1;
641         cp2= (char *)&col2;
642         cp=  (char *)&col;
643         
644         /* See if were darker, if so mix, else dont do anything.
645         if the paint col is brighter then the original, then ignore */
646         if (cp1[1]+cp1[2]+cp1[3] < cp2[1]+cp2[2]+cp2[3])
647                 return col1;
648         
649         cp[0]= 255;
650         cp[1]= (mfac*cp1[1]+fac*cp2[1])/255;
651         cp[2]= (mfac*cp1[2]+fac*cp2[2])/255;
652         cp[3]= (mfac*cp1[3]+fac*cp2[3])/255;
653         return col;
654 }
655
656 static void vpaint_blend(VPaint *vp, unsigned int *col, unsigned int *colorig, unsigned int paintcol, int alpha)
657 {
658         Brush *brush = paint_brush(&vp->paint);
659
660         if(brush->vertexpaint_tool==VP_MIX || brush->vertexpaint_tool==VP_BLUR) *col= mcol_blend( *col, paintcol, alpha);
661         else if(brush->vertexpaint_tool==VP_ADD) *col= mcol_add( *col, paintcol, alpha);
662         else if(brush->vertexpaint_tool==VP_SUB) *col= mcol_sub( *col, paintcol, alpha);
663         else if(brush->vertexpaint_tool==VP_MUL) *col= mcol_mul( *col, paintcol, alpha);
664         else if(brush->vertexpaint_tool==VP_LIGHTEN) *col= mcol_lighten( *col, paintcol, alpha);
665         else if(brush->vertexpaint_tool==VP_DARKEN) *col= mcol_darken( *col, paintcol, alpha);
666         
667         /* if no spray, clip color adding with colorig & orig alpha */
668         if((vp->flag & VP_SPRAY)==0) {
669                 unsigned int testcol=0, a;
670                 char *cp, *ct, *co;
671                 
672                 alpha= (int)(255.0f*brush_alpha(brush));
673                 
674                 if(brush->vertexpaint_tool==VP_MIX || brush->vertexpaint_tool==VP_BLUR) testcol= mcol_blend( *colorig, paintcol, alpha);
675                 else if(brush->vertexpaint_tool==VP_ADD) testcol= mcol_add( *colorig, paintcol, alpha);
676                 else if(brush->vertexpaint_tool==VP_SUB) testcol= mcol_sub( *colorig, paintcol, alpha);
677                 else if(brush->vertexpaint_tool==VP_MUL) testcol= mcol_mul( *colorig, paintcol, alpha);
678                 else if(brush->vertexpaint_tool==VP_LIGHTEN)  testcol= mcol_lighten( *colorig, paintcol, alpha);
679                 else if(brush->vertexpaint_tool==VP_DARKEN)   testcol= mcol_darken( *colorig, paintcol, alpha);
680                 
681                 cp= (char *)col;
682                 ct= (char *)&testcol;
683                 co= (char *)colorig;
684                 
685                 for(a=0; a<4; a++) {
686                         if( ct[a]<co[a] ) {
687                                 if( cp[a]<ct[a] ) cp[a]= ct[a];
688                                 else if( cp[a]>co[a] ) cp[a]= co[a];
689                         }
690                         else {
691                                 if( cp[a]<co[a] ) cp[a]= co[a];
692                                 else if( cp[a]>ct[a] ) cp[a]= ct[a];
693                         }
694                 }
695         }
696 }
697
698
699 static int sample_backbuf_area(ViewContext *vc, int *indexar, int totface, int x, int y, float size)
700 {
701         struct ImBuf *ibuf;
702         int a, tot=0, index;
703         
704         /* brecht: disabled this because it obviously failes for
705            brushes with size > 64, why is this here? */
706         /*if(size>64.0) size= 64.0;*/
707         
708         ibuf= view3d_read_backbuf(vc, x-size, y-size, x+size, y+size);
709         if(ibuf) {
710                 unsigned int *rt= ibuf->rect;
711
712                 memset(indexar, 0, sizeof(int)*(totface+1));
713                 
714                 size= ibuf->x*ibuf->y;
715                 while(size--) {
716                                 
717                         if(*rt) {
718                                 index= WM_framebuffer_to_index(*rt);
719                                 if(index>0 && index<=totface)
720                                         indexar[index] = 1;
721                         }
722                 
723                         rt++;
724                 }
725                 
726                 for(a=1; a<=totface; a++) {
727                         if(indexar[a]) indexar[tot++]= a;
728                 }
729
730                 IMB_freeImBuf(ibuf);
731         }
732         
733         return tot;
734 }
735
736 static float calc_vp_alpha_dl(VPaint *vp, ViewContext *vc, float vpimat[][3], float *vert_nor, const float mval[2], float pressure)
737 {
738         Brush *brush = paint_brush(&vp->paint);
739         float fac, fac_2, size, dx, dy;
740         float alpha;
741         int vertco[2];
742         const int radius= brush_size(brush);
743
744         project_int_noclip(vc->ar, vert_nor, vertco);
745         dx= mval[0]-vertco[0];
746         dy= mval[1]-vertco[1];
747         
748         if (brush_use_size_pressure(brush))
749                 size = pressure * radius;
750         else
751                 size = radius;
752         
753         fac_2= dx*dx + dy*dy;
754         if(fac_2 > size*size) return 0.f;
755         fac = sqrtf(fac_2);
756         
757         alpha= brush_alpha(brush) * brush_curve_strength_clamp(brush, fac, size);
758         
759         if (brush_use_alpha_pressure(brush))
760                 alpha *= pressure;
761                 
762         if(vp->flag & VP_NORMALS) {
763                 float *no= vert_nor+3;
764                 
765                 /* transpose ! */
766                 fac= vpimat[2][0]*no[0]+vpimat[2][1]*no[1]+vpimat[2][2]*no[2];
767                 if(fac > 0.0f) {
768                         dx= vpimat[0][0]*no[0]+vpimat[0][1]*no[1]+vpimat[0][2]*no[2];
769                         dy= vpimat[1][0]*no[0]+vpimat[1][1]*no[1]+vpimat[1][2]*no[2];
770                         
771                         alpha*= fac/sqrtf(dx*dx + dy*dy + fac*fac);
772                 }
773                 else return 0.f;
774         }
775         
776         return alpha;
777 }
778
779 static void wpaint_blend(VPaint *wp, MDeformWeight *dw, MDeformWeight *uw, float alpha, float paintval, int flip)
780 {
781         Brush *brush = paint_brush(&wp->paint);
782         int tool = brush->vertexpaint_tool;
783         
784         if(dw==NULL || uw==NULL) return;
785         
786         if (flip) {
787                 switch(tool) {
788                         case VP_MIX:
789                                 paintval = 1.f - paintval; break;
790                         case VP_ADD:
791                                 tool= VP_SUB; break;
792                         case VP_SUB:
793                                 tool= VP_ADD; break;
794                         case VP_LIGHTEN:
795                                 tool= VP_DARKEN; break;
796                         case VP_DARKEN:
797                                 tool= VP_LIGHTEN; break;
798                 }
799         }
800         
801         if(tool==VP_MIX || tool==VP_BLUR)
802                 dw->weight = paintval*alpha + dw->weight*(1.0f-alpha);
803         else if(tool==VP_ADD)
804                 dw->weight += paintval*alpha;
805         else if(tool==VP_SUB) 
806                 dw->weight -= paintval*alpha;
807         else if(tool==VP_MUL) 
808                 /* first mul, then blend the fac */
809                 dw->weight = ((1.0f-alpha) + alpha*paintval)*dw->weight;
810         else if(tool==VP_LIGHTEN) {
811                 if (dw->weight < paintval)
812                         dw->weight = paintval*alpha + dw->weight*(1.0f-alpha);
813         } else if(tool==VP_DARKEN) {
814                 if (dw->weight > paintval)
815                         dw->weight = paintval*alpha + dw->weight*(1.0f-alpha);
816         }
817         CLAMP(dw->weight, 0.0f, 1.0f);
818         
819         /* if no spray, clip result with orig weight & orig alpha */
820         if((wp->flag & VP_SPRAY)==0) {
821                 float testw=0.0f;
822                 
823                 alpha= brush_alpha(brush);
824                 if(tool==VP_MIX || tool==VP_BLUR)
825                         testw = paintval*alpha + uw->weight*(1.0f-alpha);
826                 else if(tool==VP_ADD)
827                         testw = uw->weight + paintval*alpha;
828                 else if(tool==VP_SUB) 
829                         testw = uw->weight - paintval*alpha;
830                 else if(tool==VP_MUL) 
831                         /* first mul, then blend the fac */
832                         testw = ((1.0f-alpha) + alpha*paintval)*uw->weight;
833                 else if(tool==VP_LIGHTEN) {
834                         if (uw->weight < paintval)
835                                 testw = paintval*alpha + uw->weight*(1.0f-alpha);
836                         else
837                                 testw = uw->weight;
838                 } else if(tool==VP_DARKEN) {
839                         if (uw->weight > paintval)
840                                 testw = paintval*alpha + uw->weight*(1.0f-alpha);
841                         else
842                                 testw = uw->weight;
843                 }
844                 CLAMP(testw, 0.0f, 1.0f);
845                 
846                 if( testw<uw->weight ) {
847                         if(dw->weight < testw) dw->weight= testw;
848                         else if(dw->weight > uw->weight) dw->weight= uw->weight;
849                 }
850                 else {
851                         if(dw->weight > testw) dw->weight= testw;
852                         else if(dw->weight < uw->weight) dw->weight= uw->weight;
853                 }
854         }
855         
856 }
857
858 /* ----------------------------------------------------- */
859
860
861 /* sets wp->weight to the closest weight value to vertex */
862 /* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */
863 static int weight_sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
864 {
865         ViewContext vc;
866         Mesh *me;
867         short change= FALSE;
868
869         view3d_set_viewcontext(C, &vc);
870         me= get_mesh(vc.obact);
871
872         if (me && me->dvert && vc.v3d && vc.rv3d) {
873                 int index;
874
875                 view3d_operator_needs_opengl(C);
876
877                 index= view3d_sample_backbuf(&vc, event->mval[0], event->mval[1]);
878
879                 if(index && index<=me->totface) {
880                         DerivedMesh *dm= mesh_get_derived_final(vc.scene, vc.obact, CD_MASK_BAREMESH);
881
882                         if(dm->getVertCo==NULL) {
883                                 BKE_report(op->reports, RPT_WARNING, "The modifier used does not support deformed locations");
884                         }
885                         else {
886                                 MFace *mf= ((MFace *)me->mface) + index-1;
887                                 const int vgroup= vc.obact->actdef - 1;
888                                 ToolSettings *ts= vc.scene->toolsettings;
889                                 float mval_f[2];
890                                 int v_idx_best= -1;
891                                 int fidx;
892                                 float len_best= FLT_MAX;
893
894                                 mval_f[0]= (float)event->mval[0];
895                                 mval_f[1]= (float)event->mval[1];
896
897                                 fidx= mf->v4 ? 3:2;
898                                 do {
899                                         float co[3], sco[3], len;
900                                         const int v_idx= (*(&mf->v1 + fidx));
901                                         dm->getVertCo(dm, v_idx, co);
902                                         project_float_noclip(vc.ar, co, sco);
903                                         len= len_squared_v2v2(mval_f, sco);
904                                         if(len < len_best) {
905                                                 len_best= len;
906                                                 v_idx_best= v_idx;
907                                         }
908                                 } while (fidx--);
909
910                                 if(v_idx_best != -1) { /* should always be valid */
911                                         ts->vgroup_weight= defvert_find_weight(&me->dvert[v_idx_best], vgroup);
912                                         change= TRUE;
913                                 }
914                         }
915                         dm->release(dm);
916                 }
917         }
918
919         if(change) {
920                 /* not really correct since the brush didnt change, but redraws the toolbar */
921                 WM_main_add_notifier(NC_BRUSH|NA_EDITED, NULL); /* ts->wpaint->paint.brush */
922
923                 return OPERATOR_FINISHED;
924         }
925         else {
926                 return OPERATOR_CANCELLED;
927         }
928 }
929
930 void PAINT_OT_weight_sample(wmOperatorType *ot)
931 {
932         /* identifiers */
933         ot->name= "Weight Paint Sample Weight";
934         ot->idname= "PAINT_OT_weight_sample";
935
936         /* api callbacks */
937         ot->invoke= weight_sample_invoke;
938         ot->poll= weight_paint_mode_poll;
939
940         /* flags */
941         ot->flag= OPTYPE_UNDO;
942 }
943
944 /* samples cursor location, and gives menu with vertex groups to activate */
945 static EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
946 {
947         if (C) {
948                 wmWindow *win= CTX_wm_window(C);
949                 if(win && win->eventstate) {
950                         ViewContext vc;
951                         Mesh *me;
952
953                         view3d_set_viewcontext(C, &vc);
954                         me= get_mesh(vc.obact);
955
956                         if (me && me->dvert && vc.v3d && vc.rv3d) {
957                                 int index;
958
959                                 view3d_operator_needs_opengl(C);
960
961                                 index= view3d_sample_backbuf(&vc, win->eventstate->x - vc.ar->winrct.xmin, win->eventstate->y - vc.ar->winrct.ymin);
962
963                                 if(index && index<=me->totface) {
964                                         const int totgroup= BLI_countlist(&vc.obact->defbase);
965                                         if(totgroup) {
966                                                 MFace *mf= ((MFace *)me->mface) + index-1;
967                                                 int fidx= mf->v4 ? 3:2;
968                                                 int *groups= MEM_callocN(totgroup*sizeof(int), "groups");
969                                                 int found= FALSE;
970
971                                                 do {
972                                                         MDeformVert *dvert= me->dvert + (*(&mf->v1 + fidx));
973                                                         int i= dvert->totweight;
974                                                         MDeformWeight *dw;
975                                                         for(dw= dvert->dw; i > 0; dw++, i--) {
976                                                                 groups[dw->def_nr]= TRUE;
977                                                                 found= TRUE;
978                                                         }
979                                                 } while (fidx--);
980
981                                                 if(found==FALSE) {
982                                                         MEM_freeN(groups);
983                                                 }
984                                                 else {
985                                                         EnumPropertyItem *item= NULL, item_tmp= {0};
986                                                         int totitem= 0;
987                                                         int i= 0;
988                                                         bDeformGroup *dg;
989                                                         for(dg= vc.obact->defbase.first; dg && i<totgroup; i++, dg= dg->next) {
990                                                                 if(groups[i]) {
991                                                                         item_tmp.identifier= item_tmp.name= dg->name;
992                                                                         item_tmp.value= i;
993                                                                         RNA_enum_item_add(&item, &totitem, &item_tmp);
994                                                                 }
995                                                         }
996
997                                                         RNA_enum_item_end(&item, &totitem);
998                                                         *free= 1;
999
1000                                                         MEM_freeN(groups);
1001                                                         return item;
1002                                                 }
1003                                         }
1004                                 }
1005                         }
1006                 }
1007         }
1008
1009         return DummyRNA_NULL_items;
1010 }
1011
1012 static int weight_sample_group_exec(bContext *C, wmOperator *op)
1013 {
1014         int type= RNA_enum_get(op->ptr, "group");
1015         ViewContext vc;
1016         view3d_set_viewcontext(C, &vc);
1017
1018         vc.obact->actdef= type + 1;
1019
1020         DAG_id_tag_update(&vc.obact->id, OB_RECALC_DATA);
1021         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, vc.obact);
1022         return OPERATOR_FINISHED;
1023 }
1024
1025 /* TODO, we could make this a menu into OBJECT_OT_vertex_group_set_active rather then its own operator */
1026 void PAINT_OT_weight_sample_group(wmOperatorType *ot)
1027 {
1028         PropertyRNA *prop= NULL;
1029
1030         /* identifiers */
1031         ot->name= "Weight Paint Sample Group";
1032         ot->idname= "PAINT_OT_weight_sample_group";
1033
1034         /* api callbacks */
1035         ot->exec= weight_sample_group_exec;
1036         ot->invoke= WM_menu_invoke;
1037         ot->poll= weight_paint_mode_poll;
1038
1039         /* flags */
1040         ot->flag= OPTYPE_UNDO;
1041
1042         /* keyingset to use (dynamic enum) */
1043         prop= RNA_def_enum(ot->srna, "group", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use");
1044         RNA_def_enum_funcs(prop, weight_paint_sample_enum_itemf);
1045         ot->prop= prop;
1046 }
1047
1048
1049 static void do_weight_paint_auto_normalize(MDeformVert *dvert, 
1050                                            int paint_nr, char *map)
1051 {
1052 //      MDeformWeight *dw = dvert->dw;
1053         float sum=0.0f, fac=0.0f, paintw=0.0f;
1054         int i, tot=0;
1055
1056         if (!map)
1057                 return;
1058
1059         for (i=0; i<dvert->totweight; i++) {
1060                 if (dvert->dw[i].def_nr == paint_nr)
1061                         paintw = dvert->dw[i].weight;
1062
1063                 if (map[dvert->dw[i].def_nr]) {
1064                         tot += 1;
1065                         if (dvert->dw[i].def_nr != paint_nr)
1066                                 sum += dvert->dw[i].weight;
1067                 }
1068         }
1069         
1070         if (!tot || sum <= (1.0f - paintw))
1071                 return;
1072
1073         fac = sum / (1.0f - paintw);
1074         fac = fac==0.0f ? 1.0f : 1.0f / fac;
1075
1076         for (i=0; i<dvert->totweight; i++) {
1077                 if (map[dvert->dw[i].def_nr]) {
1078                         if (dvert->dw[i].def_nr != paint_nr)
1079                                 dvert->dw[i].weight *= fac;
1080                 }
1081         }
1082 }
1083
1084 static void do_weight_paint_vertex(VPaint *wp, Object *ob, int index, 
1085                                    float alpha, float paintweight, int flip, 
1086                                    int vgroup_mirror, char *validmap)
1087 {
1088         Mesh *me= ob->data;
1089         MDeformWeight *dw, *uw;
1090         int vgroup= ob->actdef-1;
1091         
1092         if(wp->flag & VP_ONLYVGROUP) {
1093                 dw= defvert_find_index(me->dvert+index, vgroup);
1094                 uw= defvert_find_index(wp->wpaint_prev+index, vgroup);
1095         }
1096         else {
1097                 dw= defvert_verify_index(me->dvert+index, vgroup);
1098                 uw= defvert_verify_index(wp->wpaint_prev+index, vgroup);
1099         }
1100         if(dw==NULL || uw==NULL)
1101                 return;
1102         
1103         wpaint_blend(wp, dw, uw, alpha, paintweight, flip);
1104         do_weight_paint_auto_normalize(me->dvert+index, vgroup, validmap);
1105
1106         if(me->editflag & ME_EDIT_MIRROR_X) {   /* x mirror painting */
1107                 int j= mesh_get_x_mirror_vert(ob, index);
1108                 if(j>=0) {
1109                         /* copy, not paint again */
1110                         if(vgroup_mirror != -1)
1111                                 uw= defvert_verify_index(me->dvert+j, vgroup_mirror);
1112                         else
1113                                 uw= defvert_verify_index(me->dvert+j, vgroup);
1114                                 
1115                         uw->weight= dw->weight;
1116
1117                         do_weight_paint_auto_normalize(me->dvert+j, vgroup, validmap);
1118                 }
1119         }
1120 }
1121
1122
1123 /* *************** set wpaint operator ****************** */
1124
1125 static int set_wpaint(bContext *C, wmOperator *UNUSED(op))              /* toggle */
1126 {               
1127         Object *ob= CTX_data_active_object(C);
1128         Scene *scene= CTX_data_scene(C);
1129         VPaint *wp= scene->toolsettings->wpaint;
1130         Mesh *me;
1131         
1132         me= get_mesh(ob);
1133         if(ob->id.lib || me==NULL) return OPERATOR_PASS_THROUGH;
1134         
1135         if(ob->mode & OB_MODE_WEIGHT_PAINT) ob->mode &= ~OB_MODE_WEIGHT_PAINT;
1136         else ob->mode |= OB_MODE_WEIGHT_PAINT;
1137         
1138         
1139         /* Weightpaint works by overriding colors in mesh,
1140                 * so need to make sure we recalc on enter and
1141                 * exit (exit needs doing regardless because we
1142                                 * should redeform).
1143                 */
1144         DAG_id_tag_update(&me->id, 0);
1145         
1146         if(ob->mode & OB_MODE_WEIGHT_PAINT) {
1147                 Object *par;
1148                 
1149                 if(wp==NULL)
1150                         wp= scene->toolsettings->wpaint= new_vpaint(1);
1151
1152                 paint_init(&wp->paint, PAINT_CURSOR_WEIGHT_PAINT);
1153                 paint_cursor_start(C, weight_paint_poll);
1154                 
1155                 mesh_octree_table(ob, NULL, NULL, 's');
1156                 
1157                 /* verify if active weight group is also active bone */
1158                 par= modifiers_isDeformedByArmature(ob);
1159                 if(par && (par->mode & OB_MODE_POSE)) {
1160                         bArmature *arm= par->data;
1161
1162                         if(arm->act_bone)
1163                                 ED_vgroup_select_by_name(ob, arm->act_bone->name);
1164                 }
1165         }
1166         else {
1167                 mesh_octree_table(NULL, NULL, NULL, 'e');
1168                 mesh_mirrtopo_table(NULL, 'e');
1169         }
1170         
1171         WM_event_add_notifier(C, NC_SCENE|ND_MODE, scene);
1172         
1173         return OPERATOR_FINISHED;
1174 }
1175
1176 /* for switching to/from mode */
1177 static int paint_poll_test(bContext *C)
1178 {
1179         if(CTX_data_edit_object(C))
1180                 return 0;
1181         if(CTX_data_active_object(C)==NULL)
1182                 return 0;
1183         return 1;
1184 }
1185
1186 void PAINT_OT_weight_paint_toggle(wmOperatorType *ot)
1187 {
1188         
1189         /* identifiers */
1190         ot->name= "Weight Paint Mode";
1191         ot->idname= "PAINT_OT_weight_paint_toggle";
1192         
1193         /* api callbacks */
1194         ot->exec= set_wpaint;
1195         ot->poll= paint_poll_test;
1196         
1197         /* flags */
1198         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1199         
1200 }
1201
1202 /* ************ weight paint operator ********** */
1203
1204 struct WPaintData {
1205         ViewContext vc;
1206         int *indexar;
1207         int vgroup_mirror;
1208         float *vertexcosnos;
1209         float wpimat[3][3];
1210         
1211         /*variables for auto normalize*/
1212         int auto_normalize;
1213         char *vgroup_validmap; /*stores if vgroups tie to deforming bones or not*/
1214 };
1215
1216 static char *wpaint_make_validmap(Object *ob)
1217 {
1218         bDeformGroup *dg;
1219         ModifierData *md;
1220         char *validmap;
1221         bPose *pose;
1222         bPoseChannel *chan;
1223         ArmatureModifierData *amd;
1224         GHash *gh = BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "wpaint_make_validmap gh");
1225         int i = 0, step1=1;
1226
1227         /*add all names to a hash table*/
1228         for (dg=ob->defbase.first, i=0; dg; dg=dg->next, i++) {
1229                 BLI_ghash_insert(gh, dg->name, NULL);
1230         }
1231
1232         if (!i)
1233                 return NULL;
1234
1235         validmap = MEM_callocN(i, "wpaint valid map");
1236
1237         /*now loop through the armature modifiers and identify deform bones*/
1238         for (md = ob->modifiers.first; md; md= !md->next && step1 ? (step1=0), modifiers_getVirtualModifierList(ob) : md->next) {
1239                 if (!(md->mode & (eModifierMode_Realtime|eModifierMode_Virtual)))
1240                         continue;
1241
1242                 if (md->type == eModifierType_Armature) 
1243                 {
1244                         amd = (ArmatureModifierData*) md;
1245
1246                         if(amd->object && amd->object->pose) {
1247                                 pose = amd->object->pose;
1248                                 
1249                                 for (chan=pose->chanbase.first; chan; chan=chan->next) {
1250                                         if (chan->bone->flag & BONE_NO_DEFORM)
1251                                                 continue;
1252
1253                                         if (BLI_ghash_haskey(gh, chan->name)) {
1254                                                 BLI_ghash_remove(gh, chan->name, NULL, NULL);
1255                                                 BLI_ghash_insert(gh, chan->name, SET_INT_IN_POINTER(1));
1256                                         }
1257                                 }
1258                         }
1259                 }
1260         }
1261         
1262         /*add all names to a hash table*/
1263         for (dg=ob->defbase.first, i=0; dg; dg=dg->next, i++) {
1264                 if (BLI_ghash_lookup(gh, dg->name) != NULL) {
1265                         validmap[i] = 1;
1266                 }
1267         }
1268
1269         BLI_ghash_free(gh, NULL, NULL);
1270
1271         return validmap;
1272 }
1273
1274 static int wpaint_stroke_test_start(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1275 {
1276         Scene *scene= CTX_data_scene(C);
1277         struct PaintStroke *stroke = op->customdata;
1278         ToolSettings *ts= CTX_data_tool_settings(C);
1279         VPaint *wp= ts->wpaint;
1280         Object *ob= CTX_data_active_object(C);
1281         struct WPaintData *wpd;
1282         Mesh *me;
1283         float mat[4][4], imat[4][4];
1284         
1285         if(scene->obedit) return OPERATOR_CANCELLED;
1286         
1287         me= get_mesh(ob);
1288         if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH;
1289         
1290         /* if nothing was added yet, we make dverts and a vertex deform group */
1291         if (!me->dvert) {
1292                 ED_vgroup_data_create(&me->id);
1293                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
1294         }
1295         
1296         /* make mode data storage */
1297         wpd= MEM_callocN(sizeof(struct WPaintData), "WPaintData");
1298         paint_stroke_set_mode_data(stroke, wpd);
1299         view3d_set_viewcontext(C, &wpd->vc);
1300         wpd->vgroup_mirror= -1;
1301         
1302         /*set up auto-normalize, and generate map for detecting which
1303           vgroups affect deform bones*/
1304         wpd->auto_normalize = ts->auto_normalize;
1305         if (wpd->auto_normalize)
1306                 wpd->vgroup_validmap = wpaint_make_validmap(ob);
1307         
1308         //      if(qual & LR_CTRLKEY) {
1309         //              sample_wpaint(scene, ar, v3d, 0);
1310         //              return;
1311         //      }
1312         //      if(qual & LR_SHIFTKEY) {
1313         //              sample_wpaint(scene, ar, v3d, 1);
1314         //              return;
1315         //      }
1316         
1317         /* ALLOCATIONS! no return after this line */
1318         /* painting on subsurfs should give correct points too, this returns me->totvert amount */
1319         wpd->vertexcosnos= mesh_get_mapped_verts_nors(scene, ob);
1320         wpd->indexar= get_indexarray(me);
1321         copy_wpaint_prev(wp, me->dvert, me->totvert);
1322         
1323         /* this happens on a Bone select, when no vgroup existed yet */
1324         if(ob->actdef<=0) {
1325                 Object *modob;
1326                 if((modob = modifiers_isDeformedByArmature(ob))) {
1327                         Bone *actbone= ((bArmature *)modob->data)->act_bone;
1328                         if(actbone) {
1329                                 bPoseChannel *pchan= get_pose_channel(modob->pose, actbone->name);
1330
1331                                 if(pchan) {
1332                                         bDeformGroup *dg= defgroup_find_name(ob, pchan->name);
1333                                         if(dg==NULL)
1334                                                 dg= ED_vgroup_add_name(ob, pchan->name);        /* sets actdef */
1335                                         else
1336                                                 ob->actdef= 1 + defgroup_find_index(ob, dg);
1337                                 }
1338                         }
1339                 }
1340         }
1341         if(ob->defbase.first==NULL) {
1342                 ED_vgroup_add(ob);
1343         }
1344         
1345         //      if(ob->lay & v3d->lay); else error("Active object is not in this layer");
1346         
1347         /* imat for normals */
1348         mul_m4_m4m4(mat, ob->obmat, wpd->vc.rv3d->viewmat);
1349         invert_m4_m4(imat, mat);
1350         copy_m3_m4(wpd->wpimat, imat);
1351         
1352         /* if mirror painting, find the other group */
1353         if(me->editflag & ME_EDIT_MIRROR_X) {
1354                 bDeformGroup *defgroup= BLI_findlink(&ob->defbase, ob->actdef-1);
1355                 if(defgroup) {
1356                         bDeformGroup *curdef;
1357                         int actdef= 0;
1358                         char name[32];
1359
1360                         flip_side_name(name, defgroup->name, FALSE);
1361
1362                         for (curdef = ob->defbase.first; curdef; curdef=curdef->next, actdef++)
1363                                 if (!strcmp(curdef->name, name))
1364                                         break;
1365                         if(curdef==NULL) {
1366                                 int olddef= ob->actdef; /* tsk, ED_vgroup_add sets the active defgroup */
1367                                 curdef= ED_vgroup_add_name (ob, name);
1368                                 ob->actdef= olddef;
1369                         }
1370                         
1371                         if(curdef && curdef!=defgroup)
1372                                 wpd->vgroup_mirror= actdef;
1373                 }
1374         }
1375         
1376         return 1;
1377 }
1378
1379 static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
1380 {
1381         ToolSettings *ts= CTX_data_tool_settings(C);
1382         VPaint *wp= ts->wpaint;
1383         Brush *brush = paint_brush(&wp->paint);
1384         struct WPaintData *wpd= paint_stroke_mode_data(stroke);
1385         ViewContext *vc;
1386         Object *ob;
1387         Mesh *me;
1388         float mat[4][4];
1389         float paintweight;
1390         int *indexar;
1391         int totindex, index, totw, flip;
1392         float alpha;
1393         float mval[2], pressure;
1394         
1395         /* cannot paint if there is no stroke data */
1396         if (wpd == NULL) {
1397                 // XXX: force a redraw here, since even though we can't paint, 
1398                 // at least view won't freeze until stroke ends
1399                 ED_region_tag_redraw(CTX_wm_region(C));
1400                 return;
1401         }
1402                 
1403         vc= &wpd->vc;
1404         ob= vc->obact;
1405         me= ob->data;
1406         indexar= wpd->indexar;
1407         
1408         view3d_operator_needs_opengl(C);
1409                 
1410         /* load projection matrix */
1411         mul_m4_m4m4(mat, ob->obmat, vc->rv3d->persmat);
1412
1413         flip = RNA_boolean_get(itemptr, "pen_flip");
1414         pressure = RNA_float_get(itemptr, "pressure");
1415         RNA_float_get_array(itemptr, "mouse", mval);
1416         mval[0]-= vc->ar->winrct.xmin;
1417         mval[1]-= vc->ar->winrct.ymin;
1418                         
1419         swap_m4m4(wpd->vc.rv3d->persmat, mat);
1420                         
1421         /* which faces are involved */
1422         if(wp->flag & VP_AREA) {
1423                 totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush_size(brush));
1424         }
1425         else {
1426                 indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]);
1427                 if(indexar[0]) totindex= 1;
1428                 else totindex= 0;
1429         }
1430                         
1431         if(wp->flag & VP_COLINDEX) {
1432                 for(index=0; index<totindex; index++) {
1433                         if(indexar[index] && indexar[index]<=me->totface) {
1434                                 MFace *mface= ((MFace *)me->mface) + (indexar[index]-1);
1435                                                 
1436                                 if(mface->mat_nr!=ob->actcol-1) {
1437                                         indexar[index]= 0;
1438                                 }
1439                         }
1440                 }
1441         }
1442                         
1443         if((me->editflag & ME_EDIT_PAINT_MASK) && me->mface) {
1444                 for(index=0; index<totindex; index++) {
1445                         if(indexar[index] && indexar[index]<=me->totface) {
1446                                 MFace *mface= ((MFace *)me->mface) + (indexar[index]-1);
1447                                                 
1448                                 if((mface->flag & ME_FACE_SEL)==0) {
1449                                         indexar[index]= 0;
1450                                 }
1451                         }                                       
1452                 }
1453         }
1454                         
1455         /* make sure each vertex gets treated only once */
1456         /* and calculate filter weight */
1457         totw= 0;
1458         if(brush->vertexpaint_tool==VP_BLUR) 
1459                 paintweight= 0.0f;
1460         else
1461                 paintweight= ts->vgroup_weight;
1462                         
1463         for(index=0; index<totindex; index++) {
1464                 if(indexar[index] && indexar[index]<=me->totface) {
1465                         MFace *mface= me->mface + (indexar[index]-1);
1466                                         
1467                         (me->dvert+mface->v1)->flag= 1;
1468                         (me->dvert+mface->v2)->flag= 1;
1469                         (me->dvert+mface->v3)->flag= 1;
1470                         if(mface->v4) (me->dvert+mface->v4)->flag= 1;
1471                                         
1472                         if(brush->vertexpaint_tool==VP_BLUR) {
1473                                 MDeformWeight *dw, *(*dw_func)(MDeformVert *, const int);
1474                                                 
1475                                 if(wp->flag & VP_ONLYVGROUP)
1476                                         dw_func= (MDeformWeight *(*)(MDeformVert *, const int))defvert_find_index;
1477                                 else
1478                                         dw_func= defvert_verify_index;
1479                                                 
1480                                 dw= dw_func(me->dvert+mface->v1, ob->actdef-1);
1481                                 if(dw) {paintweight+= dw->weight; totw++;}
1482                                 dw= dw_func(me->dvert+mface->v2, ob->actdef-1);
1483                                 if(dw) {paintweight+= dw->weight; totw++;}
1484                                 dw= dw_func(me->dvert+mface->v3, ob->actdef-1);
1485                                 if(dw) {paintweight+= dw->weight; totw++;}
1486                                 if(mface->v4) {
1487                                         dw= dw_func(me->dvert+mface->v4, ob->actdef-1);
1488                                         if(dw) {paintweight+= dw->weight; totw++;}
1489                                 }
1490                         }
1491                 }
1492         }
1493                         
1494         if(brush->vertexpaint_tool==VP_BLUR) 
1495                 paintweight/= (float)totw;
1496                         
1497         for(index=0; index<totindex; index++) {
1498                                 
1499                 if(indexar[index] && indexar[index]<=me->totface) {
1500                         MFace *mface= me->mface + (indexar[index]-1);
1501                                         
1502                         if((me->dvert+mface->v1)->flag) {
1503                                 alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v1, mval, pressure);
1504                                 if(alpha) {
1505                                         do_weight_paint_vertex(wp, ob, mface->v1, 
1506                                                 alpha, paintweight, flip, wpd->vgroup_mirror, 
1507                                                 wpd->vgroup_validmap);
1508                                 }
1509                                 (me->dvert+mface->v1)->flag= 0;
1510                         }
1511                                         
1512                         if((me->dvert+mface->v2)->flag) {
1513                                 alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v2, mval, pressure);
1514                                 if(alpha) {
1515                                         do_weight_paint_vertex(wp, ob, mface->v2, 
1516                                                 alpha, paintweight, flip, wpd->vgroup_mirror, 
1517                                                 wpd->vgroup_validmap);
1518                                 }
1519                                 (me->dvert+mface->v2)->flag= 0;
1520                         }
1521                                         
1522                         if((me->dvert+mface->v3)->flag) {
1523                                 alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v3, mval, pressure);
1524                                 if(alpha) {
1525                                         do_weight_paint_vertex(wp, ob, mface->v3, 
1526                                                 alpha, paintweight, flip, wpd->vgroup_mirror, 
1527                                                 wpd->vgroup_validmap);
1528                                 }
1529                                 (me->dvert+mface->v3)->flag= 0;
1530                         }
1531                                         
1532                         if((me->dvert+mface->v4)->flag) {
1533                                 if(mface->v4) {
1534                                         alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v4, mval, pressure);
1535                                         if(alpha) {
1536                                                 do_weight_paint_vertex(wp, ob, mface->v4, 
1537                                                         alpha, paintweight, flip, wpd->vgroup_mirror,
1538                                                         wpd->vgroup_validmap);
1539                                         }
1540                                         (me->dvert+mface->v4)->flag= 0;
1541                                 }
1542                         }
1543                 }
1544         }
1545                         
1546         swap_m4m4(vc->rv3d->persmat, mat);
1547                         
1548         DAG_id_tag_update(ob->data, 0);
1549         ED_region_tag_redraw(vc->ar);
1550 }
1551
1552 static void wpaint_stroke_done(bContext *C, struct PaintStroke *stroke)
1553 {
1554         ToolSettings *ts= CTX_data_tool_settings(C);
1555         Object *ob= CTX_data_active_object(C);
1556         struct WPaintData *wpd= paint_stroke_mode_data(stroke);
1557         
1558         if(wpd) {
1559                 if(wpd->vertexcosnos)
1560                         MEM_freeN(wpd->vertexcosnos);
1561                 MEM_freeN(wpd->indexar);
1562                 
1563                 if (wpd->vgroup_validmap)
1564                         MEM_freeN(wpd->vgroup_validmap);
1565                 
1566                 MEM_freeN(wpd);
1567         }
1568         
1569         /* frees prev buffer */
1570         copy_wpaint_prev(ts->wpaint, NULL, 0);
1571         
1572         /* and particles too */
1573         if(ob->particlesystem.first) {
1574                 ParticleSystem *psys;
1575                 int i;
1576                 
1577                 for(psys= ob->particlesystem.first; psys; psys= psys->next) {
1578                         for(i=0; i<PSYS_TOT_VG; i++) {
1579                                 if(psys->vgroup[i]==ob->actdef) {
1580                                         psys->recalc |= PSYS_RECALC_RESET;
1581                                         break;
1582                                 }
1583                         }
1584                 }
1585         }
1586         
1587         DAG_id_tag_update(ob->data, 0);
1588 }
1589
1590
1591 static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
1592 {
1593         
1594         op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start,
1595                                           wpaint_stroke_update_step,
1596                                           wpaint_stroke_done, event->type);
1597         
1598         /* add modal handler */
1599         WM_event_add_modal_handler(C, op);
1600
1601         op->type->modal(C, op, event);
1602         
1603         return OPERATOR_RUNNING_MODAL;
1604 }
1605
1606 void PAINT_OT_weight_paint(wmOperatorType *ot)
1607 {
1608         
1609         /* identifiers */
1610         ot->name= "Weight Paint";
1611         ot->idname= "PAINT_OT_weight_paint";
1612         
1613         /* api callbacks */
1614         ot->invoke= wpaint_invoke;
1615         ot->modal= paint_stroke_modal;
1616         /* ot->exec= vpaint_exec; <-- needs stroke property */
1617         ot->poll= weight_paint_poll;
1618         
1619         /* flags */
1620         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
1621
1622         RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
1623 }
1624
1625 static int weight_paint_set_exec(bContext *C, wmOperator *UNUSED(op))
1626 {
1627         struct Scene *scene= CTX_data_scene(C);
1628         Object *obact = CTX_data_active_object(C);
1629
1630         wpaint_fill(scene->toolsettings->wpaint, obact, scene->toolsettings->vgroup_weight);
1631         ED_region_tag_redraw(CTX_wm_region(C)); // XXX - should redraw all 3D views
1632         return OPERATOR_FINISHED;
1633 }
1634
1635 void PAINT_OT_weight_set(wmOperatorType *ot)
1636 {
1637         /* identifiers */
1638         ot->name= "Set Weight";
1639         ot->idname= "PAINT_OT_weight_set";
1640
1641         /* api callbacks */
1642         ot->exec= weight_paint_set_exec;
1643         ot->poll= facemask_paint_poll;
1644
1645         /* flags */
1646         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1647 }
1648
1649 /* ************ set / clear vertex paint mode ********** */
1650
1651
1652 static int set_vpaint(bContext *C, wmOperator *op)              /* toggle */
1653 {       
1654         Object *ob= CTX_data_active_object(C);
1655         Scene *scene= CTX_data_scene(C);
1656         VPaint *vp= scene->toolsettings->vpaint;
1657         Mesh *me;
1658         
1659         me= get_mesh(ob);
1660         
1661         if(me==NULL || object_data_is_libdata(ob)) {
1662                 ob->mode &= ~OB_MODE_VERTEX_PAINT;
1663                 return OPERATOR_PASS_THROUGH;
1664         }
1665         
1666         if(me && me->mcol==NULL) make_vertexcol(ob);
1667         
1668         /* toggle: end vpaint */
1669         if(ob->mode & OB_MODE_VERTEX_PAINT) {
1670                 
1671                 ob->mode &= ~OB_MODE_VERTEX_PAINT;
1672         }
1673         else {
1674                 ob->mode |= OB_MODE_VERTEX_PAINT;
1675                 /* Turn off weight painting */
1676                 if (ob->mode & OB_MODE_WEIGHT_PAINT)
1677                         set_wpaint(C, op);
1678                 
1679                 if(vp==NULL)
1680                         vp= scene->toolsettings->vpaint= new_vpaint(0);
1681                 
1682                 paint_cursor_start(C, vertex_paint_poll);
1683
1684                 paint_init(&vp->paint, PAINT_CURSOR_VERTEX_PAINT);
1685         }
1686         
1687         if (me)
1688                 /* update modifier stack for mapping requirements */
1689                 DAG_id_tag_update(&me->id, 0);
1690         
1691         WM_event_add_notifier(C, NC_SCENE|ND_MODE, scene);
1692         
1693         return OPERATOR_FINISHED;
1694 }
1695
1696 void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
1697 {
1698         
1699         /* identifiers */
1700         ot->name= "Vertex Paint Mode";
1701         ot->idname= "PAINT_OT_vertex_paint_toggle";
1702         
1703         /* api callbacks */
1704         ot->exec= set_vpaint;
1705         ot->poll= paint_poll_test;
1706         
1707         /* flags */
1708         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1709 }
1710
1711
1712
1713 /* ********************** vertex paint operator ******************* */
1714
1715 /* Implementation notes:
1716
1717 Operator->invoke()
1718   - validate context (add mcol)
1719   - create customdata storage
1720   - call paint once (mouse click)
1721   - add modal handler 
1722
1723 Operator->modal()
1724   - for every mousemove, apply vertex paint
1725   - exit on mouse release, free customdata
1726         (return OPERATOR_FINISHED also removes handler and operator)
1727
1728 For future:
1729   - implement a stroke event (or mousemove with past positons)
1730   - revise whether op->customdata should be added in object, in set_vpaint
1731
1732 */
1733
1734 typedef struct VPaintData {
1735         ViewContext vc;
1736         unsigned int paintcol;
1737         int *indexar;
1738         float *vertexcosnos;
1739         float vpimat[3][3];
1740 } VPaintData;
1741
1742 static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *UNUSED(event))
1743 {
1744         ToolSettings *ts= CTX_data_tool_settings(C);
1745         struct PaintStroke *stroke = op->customdata;
1746         VPaint *vp= ts->vpaint;
1747         struct VPaintData *vpd;
1748         Object *ob= CTX_data_active_object(C);
1749         Mesh *me;
1750         float mat[4][4], imat[4][4];
1751
1752         /* context checks could be a poll() */
1753         me= get_mesh(ob);
1754         if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH;
1755         
1756         if(me->mcol==NULL) make_vertexcol(ob);
1757         if(me->mcol==NULL) return OPERATOR_CANCELLED;
1758         
1759         /* make mode data storage */
1760         vpd= MEM_callocN(sizeof(struct VPaintData), "VPaintData");
1761         paint_stroke_set_mode_data(stroke, vpd);
1762         view3d_set_viewcontext(C, &vpd->vc);
1763         
1764         vpd->vertexcosnos= mesh_get_mapped_verts_nors(vpd->vc.scene, ob);
1765         vpd->indexar= get_indexarray(me);
1766         vpd->paintcol= vpaint_get_current_col(vp);
1767         
1768         /* for filtering */
1769         copy_vpaint_prev(vp, (unsigned int *)me->mcol, me->totface);
1770         
1771         /* some old cruft to sort out later */
1772         mul_m4_m4m4(mat, ob->obmat, vpd->vc.rv3d->viewmat);
1773         invert_m4_m4(imat, mat);
1774         copy_m3_m4(vpd->vpimat, imat);
1775
1776         return 1;
1777 }
1778
1779 static void vpaint_paint_face(VPaint *vp, VPaintData *vpd, Object *ob, int index, const float mval[2], float pressure, int UNUSED(flip))
1780 {
1781         ViewContext *vc = &vpd->vc;
1782         Brush *brush = paint_brush(&vp->paint);
1783         Mesh *me = get_mesh(ob);
1784         MFace *mface= ((MFace*)me->mface) + index;
1785         unsigned int *mcol= ((unsigned int*)me->mcol) + 4*index;
1786         unsigned int *mcolorig= ((unsigned int*)vp->vpaint_prev) + 4*index;
1787         float alpha;
1788         int i;
1789         
1790         if((vp->flag & VP_COLINDEX && mface->mat_nr!=ob->actcol-1) ||
1791            ((me->editflag & ME_EDIT_PAINT_MASK) && !(mface->flag & ME_FACE_SEL)))
1792                 return;
1793
1794         if(brush->vertexpaint_tool==VP_BLUR) {
1795                 unsigned int fcol1= mcol_blend( mcol[0], mcol[1], 128);
1796                 if(mface->v4) {
1797                         unsigned int fcol2= mcol_blend( mcol[2], mcol[3], 128);
1798                         vpd->paintcol= mcol_blend( fcol1, fcol2, 128);
1799                 }
1800                 else {
1801                         vpd->paintcol= mcol_blend( mcol[2], fcol1, 170);
1802                 }
1803                 
1804         }
1805
1806         for(i = 0; i < (mface->v4 ? 4 : 3); ++i) {
1807                 alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*(&mface->v1)[i], mval, pressure);
1808                 if(alpha)
1809                         vpaint_blend(vp, mcol+i, mcolorig+i, vpd->paintcol, (int)(alpha*255.0f));
1810         }
1811 }
1812
1813 static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
1814 {
1815         ToolSettings *ts= CTX_data_tool_settings(C);
1816         struct VPaintData *vpd = paint_stroke_mode_data(stroke);
1817         VPaint *vp= ts->vpaint;
1818         Brush *brush = paint_brush(&vp->paint);
1819         ViewContext *vc= &vpd->vc;
1820         Object *ob= vc->obact;
1821         Mesh *me= ob->data;
1822         float mat[4][4];
1823         int *indexar= vpd->indexar;
1824         int totindex, index, flip;
1825         float pressure, mval[2];
1826
1827         RNA_float_get_array(itemptr, "mouse", mval);
1828         flip = RNA_boolean_get(itemptr, "pen_flip");
1829         pressure = RNA_float_get(itemptr, "pressure");
1830                         
1831         view3d_operator_needs_opengl(C);
1832                         
1833         /* load projection matrix */
1834         mul_m4_m4m4(mat, ob->obmat, vc->rv3d->persmat);
1835
1836         mval[0]-= vc->ar->winrct.xmin;
1837         mval[1]-= vc->ar->winrct.ymin;
1838
1839                         
1840         /* which faces are involved */
1841         if(vp->flag & VP_AREA) {
1842                 totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush_size(brush));
1843         }
1844         else {
1845                 indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]);
1846                 if(indexar[0]) totindex= 1;
1847                 else totindex= 0;
1848         }
1849                         
1850         swap_m4m4(vc->rv3d->persmat, mat);
1851                         
1852         for(index=0; index<totindex; index++) {                         
1853                 if(indexar[index] && indexar[index]<=me->totface)
1854                         vpaint_paint_face(vp, vpd, ob, indexar[index]-1, mval, pressure, flip);
1855         }
1856                                                 
1857         swap_m4m4(vc->rv3d->persmat, mat);
1858
1859         /* was disabled because it is slow, but necessary for blur */
1860         if(brush->vertexpaint_tool == VP_BLUR)
1861                 do_shared_vertexcol(me);
1862                         
1863         ED_region_tag_redraw(vc->ar);
1864                         
1865         DAG_id_tag_update(ob->data, 0);
1866 }
1867
1868 static void vpaint_stroke_done(bContext *C, struct PaintStroke *stroke)
1869 {
1870         ToolSettings *ts= CTX_data_tool_settings(C);
1871         struct VPaintData *vpd= paint_stroke_mode_data(stroke);
1872         
1873         if(vpd->vertexcosnos)
1874                 MEM_freeN(vpd->vertexcosnos);
1875         MEM_freeN(vpd->indexar);
1876         
1877         /* frees prev buffer */
1878         copy_vpaint_prev(ts->vpaint, NULL, 0);
1879         
1880         MEM_freeN(vpd);
1881 }
1882
1883 static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
1884 {
1885         
1886         op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start,
1887                                           vpaint_stroke_update_step,
1888                                           vpaint_stroke_done, event->type);
1889         
1890         /* add modal handler */
1891         WM_event_add_modal_handler(C, op);
1892
1893         op->type->modal(C, op, event);
1894         
1895         return OPERATOR_RUNNING_MODAL;
1896 }
1897
1898 void PAINT_OT_vertex_paint(wmOperatorType *ot)
1899 {
1900         /* identifiers */
1901         ot->name= "Vertex Paint";
1902         ot->idname= "PAINT_OT_vertex_paint";
1903         
1904         /* api callbacks */
1905         ot->invoke= vpaint_invoke;
1906         ot->modal= paint_stroke_modal;
1907         /* ot->exec= vpaint_exec; <-- needs stroke property */
1908         ot->poll= vertex_paint_poll;
1909         
1910         /* flags */
1911         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
1912
1913         RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
1914 }
1915
1916 /* ********************** weight from bones operator ******************* */
1917
1918 static int weight_from_bones_poll(bContext *C)
1919 {
1920         Object *ob= CTX_data_active_object(C);
1921
1922         return (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && modifiers_isDeformedByArmature(ob));
1923 }
1924
1925 static int weight_from_bones_exec(bContext *C, wmOperator *op)
1926 {
1927         Scene *scene= CTX_data_scene(C);
1928         Object *ob= CTX_data_active_object(C);
1929         Object *armob= modifiers_isDeformedByArmature(ob);
1930         Mesh *me= ob->data;
1931         int type= RNA_enum_get(op->ptr, "type");
1932
1933         create_vgroups_from_armature(op->reports, scene, ob, armob, type, (me->editflag & ME_EDIT_MIRROR_X));
1934
1935         DAG_id_tag_update(&me->id, 0);
1936         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
1937
1938         return OPERATOR_FINISHED;
1939 }
1940
1941 void PAINT_OT_weight_from_bones(wmOperatorType *ot)
1942 {
1943         static EnumPropertyItem type_items[]= {
1944                 {ARM_GROUPS_AUTO, "AUTOMATIC", 0, "Automatic", "Automatic weights froms bones"},
1945                 {ARM_GROUPS_ENVELOPE, "ENVELOPES", 0, "From Envelopes", "Weights from envelopes with user defined radius"},
1946                 {0, NULL, 0, NULL, NULL}};
1947
1948         /* identifiers */
1949         ot->name= "Weight from Bones";
1950         ot->idname= "PAINT_OT_weight_from_bones";
1951         
1952         /* api callbacks */
1953         ot->exec= weight_from_bones_exec;
1954         ot->invoke= WM_menu_invoke;
1955         ot->poll= weight_from_bones_poll;
1956         
1957         /* flags */
1958         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1959
1960         /* properties */
1961         ot->prop= RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights.");
1962 }
1963