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