2.5/Paint modes:
[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
9 #include "DNA_scene_types.h"
10 #include "DNA_screen_types.h"
11 #include "DNA_view3d_types.h"
12
13 #include "RNA_access.h"
14 #include "RNA_define.h"
15
16 #include "BLI_arithb.h"
17
18 #include "BKE_brush.h"
19 #include "BKE_context.h"
20 #include "BKE_DerivedMesh.h"
21 #include "BKE_global.h"
22 #include "BKE_utildefines.h"
23
24 #include "BIF_gl.h"
25
26 #include "ED_view3d.h"
27
28 #include "WM_api.h"
29 #include "WM_types.h"
30
31 #include "paint_intern.h"
32
33 /* 3D Paint */
34
35 static void imapaint_project(Object *ob, float *model, float *proj, float *co, float *pco)
36 {
37         VECCOPY(pco, co);
38         pco[3]= 1.0f;
39
40         Mat4MulVecfl(ob->obmat, pco);
41         Mat4MulVecfl((float(*)[4])model, pco);
42         Mat4MulVec4fl((float(*)[4])proj, pco);
43 }
44
45 static void imapaint_tri_weights(Object *ob, float *v1, float *v2, float *v3, float *co, float *w)
46 {
47         float pv1[4], pv2[4], pv3[4], h[3], divw;
48         float model[16], proj[16], wmat[3][3], invwmat[3][3];
49         GLint view[4];
50
51         /* compute barycentric coordinates */
52
53         /* get the needed opengl matrices */
54         glGetIntegerv(GL_VIEWPORT, view);
55         glGetFloatv(GL_MODELVIEW_MATRIX, model);
56         glGetFloatv(GL_PROJECTION_MATRIX, proj);
57         view[0] = view[1] = 0;
58
59         /* project the verts */
60         imapaint_project(ob, model, proj, v1, pv1);
61         imapaint_project(ob, model, proj, v2, pv2);
62         imapaint_project(ob, model, proj, v3, pv3);
63
64         /* do inverse view mapping, see gluProject man page */
65         h[0]= (co[0] - view[0])*2.0f/view[2] - 1;
66         h[1]= (co[1] - view[1])*2.0f/view[3] - 1;
67         h[2]= 1.0f;
68
69         /* solve for(w1,w2,w3)/perspdiv in:
70            h*perspdiv = Project*Model*(w1*v1 + w2*v2 + w3*v3) */
71
72         wmat[0][0]= pv1[0];  wmat[1][0]= pv2[0];  wmat[2][0]= pv3[0];
73         wmat[0][1]= pv1[1];  wmat[1][1]= pv2[1];  wmat[2][1]= pv3[1];
74         wmat[0][2]= pv1[3];  wmat[1][2]= pv2[3];  wmat[2][2]= pv3[3];
75
76         Mat3Inv(invwmat, wmat);
77         Mat3MulVecfl(invwmat, h);
78
79         VECCOPY(w, h);
80
81         /* w is still divided by perspdiv, make it sum to one */
82         divw= w[0] + w[1] + w[2];
83         if(divw != 0.0f)
84                 VecMulf(w, 1.0f/divw);
85 }
86
87 /* compute uv coordinates of mouse in face */
88 void imapaint_pick_uv(Scene *scene, Object *ob, Mesh *mesh, unsigned int faceindex, int *xy, float *uv)
89 {
90         DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
91         int *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
92         MTFace *tface = dm->getFaceDataArray(dm, CD_MTFACE), *tf;
93         int numfaces = dm->getNumFaces(dm), a;
94         float p[2], w[3], absw, minabsw;
95         MFace mf;
96         MVert mv[4];
97
98         minabsw = 1e10;
99         uv[0] = uv[1] = 0.0;
100
101         /* test all faces in the derivedmesh with the original index of the picked face */
102         for(a = 0; a < numfaces; a++) {
103                 if(index[a] == faceindex) {
104                         dm->getFace(dm, a, &mf);
105
106                         dm->getVert(dm, mf.v1, &mv[0]);
107                         dm->getVert(dm, mf.v2, &mv[1]);
108                         dm->getVert(dm, mf.v3, &mv[2]);
109                         if(mf.v4)
110                                 dm->getVert(dm, mf.v4, &mv[3]);
111
112                         tf= &tface[a];
113
114                         p[0]= xy[0];
115                         p[1]= xy[1];
116
117                         if(mf.v4) {
118                                 /* the triangle with the largest absolute values is the one
119                                    with the most negative weights */
120                                 imapaint_tri_weights(ob, mv[0].co, mv[1].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[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[3][0]*w[2];
124                                         uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[3][1]*w[2];
125                                         minabsw = absw;
126                                 }
127
128                                 imapaint_tri_weights(ob, mv[1].co, mv[2].co, mv[3].co, p, w);
129                                 absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
130                                 if(absw < minabsw) {
131                                         uv[0]= tf->uv[1][0]*w[0] + tf->uv[2][0]*w[1] + tf->uv[3][0]*w[2];
132                                         uv[1]= tf->uv[1][1]*w[0] + tf->uv[2][1]*w[1] + tf->uv[3][1]*w[2];
133                                         minabsw = absw;
134                                 }
135                         }
136                         else {
137                                 imapaint_tri_weights(ob, mv[0].co, mv[1].co, mv[2].co, p, w);
138                                 absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
139                                 if(absw < minabsw) {
140                                         uv[0]= tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[2][0]*w[2];
141                                         uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[2][1]*w[2];
142                                         minabsw = absw;
143                                 }
144                         }
145                 }
146         }
147
148         dm->release(dm);
149 }
150
151 ///* returns 0 if not found, otherwise 1 */
152 int imapaint_pick_face(ViewContext *vc, Mesh *me, int *mval, unsigned int *index)
153 {
154         if(!me || me->totface==0)
155                 return 0;
156
157         /* sample only on the exact position */
158         *index = view3d_sample_backbuf(vc, mval[0], mval[1]);
159
160         if((*index)<=0 || (*index)>(unsigned int)me->totface)
161                 return 0;
162
163         (*index)--;
164         
165         return 1;
166 }
167
168 /* used for both 3d view and image window */
169 void paint_sample_color(Scene *scene, ARegion *ar, int x, int y)        /* frontbuf */
170 {
171         Brush **br = current_brush_source(scene);
172         unsigned int col;
173         char *cp;
174
175         CLAMP(x, 0, ar->winx);
176         CLAMP(y, 0, ar->winy);
177         
178         glReadBuffer(GL_FRONT);
179         glReadPixels(x+ar->winrct.xmin, y+ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
180         glReadBuffer(GL_BACK);
181
182         cp = (char *)&col;
183         
184         if(br && *br) {
185                 (*br)->rgb[0]= cp[0]/255.0f;
186                 (*br)->rgb[1]= cp[1]/255.0f;
187                 (*br)->rgb[2]= cp[2]/255.0f;
188         }
189 }
190
191 static int brush_curve_preset_exec(bContext *C, wmOperator *op)
192 {
193         Brush *br = *current_brush_source(CTX_data_scene(C));
194         brush_curve_preset(br, RNA_enum_get(op->ptr, "shape"));
195
196         return OPERATOR_FINISHED;
197 }
198
199 static int brush_curve_preset_poll(bContext *C)
200 {
201         Brush **br = current_brush_source(CTX_data_scene(C));
202
203         return br && *br && (*br)->curve;
204 }
205
206 void BRUSH_OT_curve_preset(wmOperatorType *ot)
207 {
208         static EnumPropertyItem prop_shape_items[] = {
209                 {BRUSH_PRESET_SHARP, "SHARP", 0, "Sharp", ""},
210                 {BRUSH_PRESET_SMOOTH, "SMOOTH", 0, "Smooth", ""},
211                 {BRUSH_PRESET_MAX, "MAX", 0, "Max", ""},
212                 {0, NULL, 0, NULL, NULL}};
213
214         ot->name= "Preset";
215         ot->idname= "BRUSH_OT_curve_preset";
216
217         ot->exec= brush_curve_preset_exec;
218         ot->poll= brush_curve_preset_poll;
219
220         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
221
222         RNA_def_enum(ot->srna, "shape", prop_shape_items, BRUSH_PRESET_SHARP, "Mode", "");
223 }