Recreating my GSoC branch.
[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
11 #include "RNA_access.h"
12 #include "RNA_define.h"
13
14 #include "BLI_math.h"
15
16 #include "BKE_brush.h"
17 #include "BKE_colortools.h"
18 #include "BKE_context.h"
19 #include "BKE_DerivedMesh.h"
20 #include "BKE_global.h"
21 #include "BKE_paint.h"
22
23 #include "BKE_utildefines.h"
24
25 #include "BIF_gl.h"
26
27 #include "ED_view3d.h"
28 #include "ED_screen.h"
29
30 #include "BLO_sys_types.h"
31 #include "ED_mesh.h" /* for face mask functions */
32
33 #include "WM_api.h"
34 #include "WM_types.h"
35
36 #include "paint_intern.h"
37
38 /* 3D Paint */
39
40 static void imapaint_project(Object *ob, float *model, float *proj, float *co, float *pco)
41 {
42         VECCOPY(pco, co);
43         pco[3]= 1.0f;
44
45         mul_m4_v3(ob->obmat, pco);
46         mul_m4_v3((float(*)[4])model, pco);
47         mul_m4_v4((float(*)[4])proj, pco);
48 }
49
50 static void imapaint_tri_weights(Object *ob, float *v1, float *v2, float *v3, float *co, float *w)
51 {
52         float pv1[4], pv2[4], pv3[4], h[3], divw;
53         float model[16], proj[16], wmat[3][3], invwmat[3][3];
54         GLint view[4];
55
56         /* compute barycentric coordinates */
57
58         /* get the needed opengl matrices */
59         glGetIntegerv(GL_VIEWPORT, view);
60         glGetFloatv(GL_MODELVIEW_MATRIX, model);
61         glGetFloatv(GL_PROJECTION_MATRIX, proj);
62         view[0] = view[1] = 0;
63
64         /* project the verts */
65         imapaint_project(ob, model, proj, v1, pv1);
66         imapaint_project(ob, model, proj, v2, pv2);
67         imapaint_project(ob, model, proj, v3, pv3);
68
69         /* do inverse view mapping, see gluProject man page */
70         h[0]= (co[0] - view[0])*2.0f/view[2] - 1;
71         h[1]= (co[1] - view[1])*2.0f/view[3] - 1;
72         h[2]= 1.0f;
73
74         /* solve for(w1,w2,w3)/perspdiv in:
75            h*perspdiv = Project*Model*(w1*v1 + w2*v2 + w3*v3) */
76
77         wmat[0][0]= pv1[0];  wmat[1][0]= pv2[0];  wmat[2][0]= pv3[0];
78         wmat[0][1]= pv1[1];  wmat[1][1]= pv2[1];  wmat[2][1]= pv3[1];
79         wmat[0][2]= pv1[3];  wmat[1][2]= pv2[3];  wmat[2][2]= pv3[3];
80
81         invert_m3_m3(invwmat, wmat);
82         mul_m3_v3(invwmat, h);
83
84         VECCOPY(w, h);
85
86         /* w is still divided by perspdiv, make it sum to one */
87         divw= w[0] + w[1] + w[2];
88         if(divw != 0.0f)
89                 mul_v3_fl(w, 1.0f/divw);
90 }
91
92 /* compute uv coordinates of mouse in face */
93 void imapaint_pick_uv(Scene *scene, Object *ob, Mesh *mesh, unsigned int faceindex, int *xy, float *uv)
94 {
95         DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
96         int *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
97         MTFace *tface = dm->getFaceDataArray(dm, CD_MTFACE), *tf;
98         int numfaces = dm->getNumFaces(dm), a, findex;
99         float p[2], w[3], absw, minabsw;
100         MFace mf;
101         MVert mv[4];
102
103         minabsw = 1e10;
104         uv[0] = uv[1] = 0.0;
105
106         /* test all faces in the derivedmesh with the original index of the picked face */
107         for(a = 0; a < numfaces; a++) {
108                 findex= (index)? index[a]: a;
109
110                 if(findex == faceindex) {
111                         dm->getFace(dm, a, &mf);
112
113                         dm->getVert(dm, mf.v1, &mv[0]);
114                         dm->getVert(dm, mf.v2, &mv[1]);
115                         dm->getVert(dm, mf.v3, &mv[2]);
116                         if(mf.v4)
117                                 dm->getVert(dm, mf.v4, &mv[3]);
118
119                         tf= &tface[a];
120
121                         p[0]= xy[0];
122                         p[1]= xy[1];
123
124                         if(mf.v4) {
125                                 /* the triangle with the largest absolute values is the one
126                                    with the most negative weights */
127                                 imapaint_tri_weights(ob, mv[0].co, mv[1].co, mv[3].co, p, w);
128                                 absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
129                                 if(absw < minabsw) {
130                                         uv[0]= tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[3][0]*w[2];
131                                         uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[3][1]*w[2];
132                                         minabsw = absw;
133                                 }
134
135                                 imapaint_tri_weights(ob, mv[1].co, mv[2].co, mv[3].co, p, w);
136                                 absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
137                                 if(absw < minabsw) {
138                                         uv[0]= tf->uv[1][0]*w[0] + tf->uv[2][0]*w[1] + tf->uv[3][0]*w[2];
139                                         uv[1]= tf->uv[1][1]*w[0] + tf->uv[2][1]*w[1] + tf->uv[3][1]*w[2];
140                                         minabsw = absw;
141                                 }
142                         }
143                         else {
144                                 imapaint_tri_weights(ob, mv[0].co, mv[1].co, mv[2].co, p, w);
145                                 absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
146                                 if(absw < minabsw) {
147                                         uv[0]= tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[2][0]*w[2];
148                                         uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[2][1]*w[2];
149                                         minabsw = absw;
150                                 }
151                         }
152                 }
153         }
154
155         dm->release(dm);
156 }
157
158 ///* returns 0 if not found, otherwise 1 */
159 int imapaint_pick_face(ViewContext *vc, Mesh *me, int *mval, unsigned int *index)
160 {
161         if(!me || me->totface==0)
162                 return 0;
163
164         /* sample only on the exact position */
165         *index = view3d_sample_backbuf(vc, mval[0], mval[1]);
166
167         if((*index)<=0 || (*index)>(unsigned int)me->totface)
168                 return 0;
169
170         (*index)--;
171         
172         return 1;
173 }
174
175 /* used for both 3d view and image window */
176 void paint_sample_color(Scene *scene, ARegion *ar, int x, int y)        /* frontbuf */
177 {
178         Brush *br = paint_brush(paint_get_active(scene));
179         unsigned int col;
180         char *cp;
181
182         CLAMP(x, 0, ar->winx);
183         CLAMP(y, 0, ar->winy);
184         
185         glReadBuffer(GL_FRONT);
186         glReadPixels(x+ar->winrct.xmin, y+ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
187         glReadBuffer(GL_BACK);
188
189         cp = (char *)&col;
190         
191         if(br) {
192                 br->rgb[0]= cp[0]/255.0f;
193                 br->rgb[1]= cp[1]/255.0f;
194                 br->rgb[2]= cp[2]/255.0f;
195         }
196 }
197
198 static int brush_curve_preset_exec(bContext *C, wmOperator *op)
199 {
200         Brush *br = paint_brush(paint_get_active(CTX_data_scene(C)));
201         brush_curve_preset(br, RNA_enum_get(op->ptr, "shape"));
202
203         return OPERATOR_FINISHED;
204 }
205
206 static int brush_curve_preset_poll(bContext *C)
207 {
208         Brush *br = paint_brush(paint_get_active(CTX_data_scene(C)));
209
210         return br && br->curve;
211 }
212
213 void BRUSH_OT_curve_preset(wmOperatorType *ot)
214 {
215         static EnumPropertyItem prop_shape_items[] = {
216                 {CURVE_PRESET_SHARP, "SHARP", 0, "Sharp", ""},
217                 {CURVE_PRESET_SMOOTH, "SMOOTH", 0, "Smooth", ""},
218                 {CURVE_PRESET_MAX, "MAX", 0, "Max", ""},
219                 {0, NULL, 0, NULL, NULL}};
220
221         ot->name= "Preset";
222         ot->description= "Set brush shape";
223         ot->idname= "BRUSH_OT_curve_preset";
224
225         ot->exec= brush_curve_preset_exec;
226         ot->poll= brush_curve_preset_poll;
227
228         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
229
230         RNA_def_enum(ot->srna, "shape", prop_shape_items, CURVE_PRESET_SMOOTH, "Mode", "");
231 }
232
233
234 /* face-select ops */
235 static int paint_select_linked_exec(bContext *C, wmOperator *op)
236 {
237         select_linked_tfaces(C, CTX_data_active_object(C), NULL, 2);
238         ED_region_tag_redraw(CTX_wm_region(C));
239         return OPERATOR_FINISHED;
240 }
241
242 void PAINT_OT_face_select_linked(wmOperatorType *ot)
243 {
244         ot->name= "Select Linked";
245         ot->description= "Select linked faces";
246         ot->idname= "PAINT_OT_face_select_linked";
247
248         ot->exec= paint_select_linked_exec;
249         ot->poll= facemask_paint_poll;
250
251         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
252 }
253
254 static int paint_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
255 {
256         int mode= RNA_boolean_get(op->ptr, "extend") ? 1:0;
257         select_linked_tfaces(C, CTX_data_active_object(C), event->mval, mode);
258         ED_region_tag_redraw(CTX_wm_region(C));
259         return OPERATOR_FINISHED;
260 }
261
262 void PAINT_OT_face_select_linked_pick(wmOperatorType *ot)
263 {
264         ot->name= "Select Linked Pick";
265         ot->description= "Select linked faces";
266         ot->idname= "PAINT_OT_face_select_linked_pick";
267
268         ot->invoke= paint_select_linked_pick_invoke;
269         ot->poll= facemask_paint_poll;
270
271         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
272
273         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection");
274 }
275
276
277 static int face_select_all_exec(bContext *C, wmOperator *op)
278 {
279         selectall_tface(CTX_data_active_object(C), RNA_enum_get(op->ptr, "action"));
280         ED_region_tag_redraw(CTX_wm_region(C));
281         return OPERATOR_FINISHED;
282 }
283
284
285 void PAINT_OT_face_select_all(wmOperatorType *ot)
286 {
287         ot->name= "Face Selection";
288         ot->description= "Change selection for all faces";
289         ot->idname= "PAINT_OT_face_select_all";
290
291         ot->exec= face_select_all_exec;
292         ot->poll= facemask_paint_poll;
293
294         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
295
296         WM_operator_properties_select_all(ot);
297 }