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