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