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