2.5:
[blender.git] / source / blender / editors / sculpt_paint / paint_utils.c
1
2 #include <math.h>
3 #include <stdlib.h>
4
5 #include "DNA_mesh_types.h"
6 #include "DNA_meshdata_types.h"
7 #include "DNA_object_types.h"
8 #include "DNA_scene_types.h"
9 #include "DNA_screen_types.h"
10 #include "DNA_view3d_types.h"
11
12 #include "BLI_arithb.h"
13
14 #include "BKE_DerivedMesh.h"
15 #include "BKE_global.h"
16 #include "BKE_utildefines.h"
17
18 #include "BIF_gl.h"
19
20 #include "ED_view3d.h"
21
22 #include "paint_intern.h"
23
24 /* 3D Paint */
25
26 static void imapaint_project(Object *ob, float *model, float *proj, float *co, float *pco)
27 {
28         VECCOPY(pco, co);
29         pco[3]= 1.0f;
30
31         Mat4MulVecfl(ob->obmat, pco);
32         Mat4MulVecfl((float(*)[4])model, pco);
33         Mat4MulVec4fl((float(*)[4])proj, pco);
34 }
35
36 static void imapaint_tri_weights(Object *ob, float *v1, float *v2, float *v3, float *co, float *w)
37 {
38         float pv1[4], pv2[4], pv3[4], h[3], divw;
39         float model[16], proj[16], wmat[3][3], invwmat[3][3];
40         GLint view[4];
41
42         /* compute barycentric coordinates */
43
44         /* get the needed opengl matrices */
45         glGetIntegerv(GL_VIEWPORT, view);
46         glGetFloatv(GL_MODELVIEW_MATRIX, model);
47         glGetFloatv(GL_PROJECTION_MATRIX, proj);
48         view[0] = view[1] = 0;
49
50         /* project the verts */
51         imapaint_project(ob, model, proj, v1, pv1);
52         imapaint_project(ob, model, proj, v2, pv2);
53         imapaint_project(ob, model, proj, v3, pv3);
54
55         /* do inverse view mapping, see gluProject man page */
56         h[0]= (co[0] - view[0])*2.0f/view[2] - 1;
57         h[1]= (co[1] - view[1])*2.0f/view[3] - 1;
58         h[2]= 1.0f;
59
60         /* solve for(w1,w2,w3)/perspdiv in:
61            h*perspdiv = Project*Model*(w1*v1 + w2*v2 + w3*v3) */
62
63         wmat[0][0]= pv1[0];  wmat[1][0]= pv2[0];  wmat[2][0]= pv3[0];
64         wmat[0][1]= pv1[1];  wmat[1][1]= pv2[1];  wmat[2][1]= pv3[1];
65         wmat[0][2]= pv1[3];  wmat[1][2]= pv2[3];  wmat[2][2]= pv3[3];
66
67         Mat3Inv(invwmat, wmat);
68         Mat3MulVecfl(invwmat, h);
69
70         VECCOPY(w, h);
71
72         /* w is still divided by perspdiv, make it sum to one */
73         divw= w[0] + w[1] + w[2];
74         if(divw != 0.0f)
75                 VecMulf(w, 1.0f/divw);
76 }
77
78 /* compute uv coordinates of mouse in face */
79 void imapaint_pick_uv(Scene *scene, Object *ob, Mesh *mesh, unsigned int faceindex, int *xy, float *uv)
80 {
81         DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
82         int *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
83         MTFace *tface = dm->getFaceDataArray(dm, CD_MTFACE), *tf;
84         int numfaces = dm->getNumFaces(dm), a;
85         float p[2], w[3], absw, minabsw;
86         MFace mf;
87         MVert mv[4];
88
89         minabsw = 1e10;
90         uv[0] = uv[1] = 0.0;
91
92         /* test all faces in the derivedmesh with the original index of the picked face */
93         for(a = 0; a < numfaces; a++) {
94                 if(index[a] == faceindex) {
95                         dm->getFace(dm, a, &mf);
96
97                         dm->getVert(dm, mf.v1, &mv[0]);
98                         dm->getVert(dm, mf.v2, &mv[1]);
99                         dm->getVert(dm, mf.v3, &mv[2]);
100                         if(mf.v4)
101                                 dm->getVert(dm, mf.v4, &mv[3]);
102
103                         tf= &tface[a];
104
105                         p[0]= xy[0];
106                         p[1]= xy[1];
107
108                         if(mf.v4) {
109                                 /* the triangle with the largest absolute values is the one
110                                    with the most negative weights */
111                                 imapaint_tri_weights(ob, mv[0].co, mv[1].co, mv[3].co, p, w);
112                                 absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
113                                 if(absw < minabsw) {
114                                         uv[0]= tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[3][0]*w[2];
115                                         uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[3][1]*w[2];
116                                         minabsw = absw;
117                                 }
118
119                                 imapaint_tri_weights(ob, mv[1].co, mv[2].co, mv[3].co, p, w);
120                                 absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
121                                 if(absw < minabsw) {
122                                         uv[0]= tf->uv[1][0]*w[0] + tf->uv[2][0]*w[1] + tf->uv[3][0]*w[2];
123                                         uv[1]= tf->uv[1][1]*w[0] + tf->uv[2][1]*w[1] + tf->uv[3][1]*w[2];
124                                         minabsw = absw;
125                                 }
126                         }
127                         else {
128                                 imapaint_tri_weights(ob, mv[0].co, mv[1].co, mv[2].co, p, w);
129                                 absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
130                                 if(absw < minabsw) {
131                                         uv[0]= tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[2][0]*w[2];
132                                         uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[2][1]*w[2];
133                                         minabsw = absw;
134                                 }
135                         }
136                 }
137         }
138
139         dm->release(dm);
140 }
141
142 ///* returns 0 if not found, otherwise 1 */
143 int imapaint_pick_face(ViewContext *vc, Mesh *me, int *mval, unsigned int *index)
144 {
145         if(!me || me->totface==0)
146                 return 0;
147
148         /* sample only on the exact position */
149         *index = view3d_sample_backbuf(vc, mval[0], mval[1]);
150
151         if((*index)<=0 || (*index)>(unsigned int)me->totface)
152                 return 0;
153
154         (*index)--;
155         
156         return 1;
157 }
158
159 /* used for both 3d view and image window */
160 void paint_sample_color(Scene *scene, ARegion *ar, int x, int y)        /* frontbuf */
161 {
162         VPaint *vp= scene->toolsettings->vpaint;
163         unsigned int col;
164         char *cp;
165
166         CLAMP(x, 0, ar->winx);
167         CLAMP(y, 0, ar->winy);
168         
169         glReadBuffer(GL_FRONT);
170         glReadPixels(x+ar->winrct.xmin, y+ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
171         glReadBuffer(GL_BACK);
172
173         cp = (char *)&col;
174         
175         if(G.f & (G_VERTEXPAINT|G_WEIGHTPAINT)) {
176                 vp->r= cp[0]/255.0f;
177                 vp->g= cp[1]/255.0f;
178                 vp->b= cp[2]/255.0f;
179         }
180         else {
181                 Brush *brush= scene->toolsettings->imapaint.brush;
182
183                 if(brush) {
184                         brush->rgb[0]= cp[0]/255.0f;
185                         brush->rgb[1]= cp[1]/255.0f;
186                         brush->rgb[2]= cp[2]/255.0f;
187
188                 }
189         }
190 }
191