Blender  V2.59
paint_utils.c
Go to the documentation of this file.
00001 
00005 #include <math.h>
00006 #include <stdlib.h>
00007 
00008 #include "DNA_mesh_types.h"
00009 #include "DNA_meshdata_types.h"
00010 #include "DNA_object_types.h"
00011 
00012 #include "DNA_scene_types.h"
00013 #include "DNA_brush_types.h"
00014 
00015 #include "BLI_math.h"
00016 #include "BLI_utildefines.h"
00017 
00018 #include "BKE_brush.h"
00019 #include "BKE_context.h"
00020 #include "BKE_DerivedMesh.h"
00021 #include "BKE_paint.h"
00022 
00023 #include "RNA_access.h"
00024 #include "RNA_define.h"
00025 
00026 #include "BIF_gl.h"
00027 /* TODO: remove once projectf goes away */
00028 #include "BIF_glutil.h"
00029 
00030 #include "RE_shader_ext.h"
00031 
00032 #include "ED_view3d.h"
00033 #include "ED_screen.h"
00034 
00035 #include "BLO_sys_types.h"
00036 #include "ED_mesh.h" /* for face mask functions */
00037 
00038 #include "WM_api.h"
00039 #include "WM_types.h"
00040 
00041 #include "paint_intern.h"
00042 
00043 /* convert a point in model coordinates to 2D screen coordinates */
00044 /* TODO: can be deleted once all calls are replaced with
00045    view3d_project_float() */
00046 void projectf(bglMats *mats, const float v[3], float p[2])
00047 {
00048         double ux, uy, uz;
00049 
00050         gluProject(v[0],v[1],v[2], mats->modelview, mats->projection,
00051                    (GLint *)mats->viewport, &ux, &uy, &uz);
00052         p[0]= ux;
00053         p[1]= uy;
00054 }
00055 
00056 float paint_calc_object_space_radius(ViewContext *vc, float center[3],
00057                                      float pixel_radius)
00058 {
00059         Object *ob = vc->obact;
00060         float delta[3], scale, loc[3];
00061         float mval_f[2];
00062 
00063         mul_v3_m4v3(loc, ob->obmat, center);
00064 
00065         initgrabz(vc->rv3d, loc[0], loc[1], loc[2]);
00066 
00067         mval_f[0]= pixel_radius;
00068         mval_f[1]= 0.0f;
00069         ED_view3d_win_to_delta(vc->ar, mval_f, delta);
00070 
00071         scale= fabsf(mat4_to_scale(ob->obmat));
00072         scale= (scale == 0.0f)? 1.0f: scale;
00073 
00074         return len_v3(delta)/scale;
00075 }
00076 
00077 float paint_get_tex_pixel(Brush* br, float u, float v)
00078 {
00079         TexResult texres;
00080         float co[3];
00081         int hasrgb;
00082 
00083         co[0] = u;
00084         co[1] = v;
00085         co[2] = 0;
00086 
00087         memset(&texres, 0, sizeof(TexResult));
00088         hasrgb = multitex_ext(br->mtex.tex, co, NULL, NULL, 0, &texres);
00089 
00090         if (hasrgb & TEX_RGB)
00091                 texres.tin = (0.35f*texres.tr + 0.45f*texres.tg + 0.2f*texres.tb)*texres.ta;
00092 
00093         return texres.tin;
00094 }
00095 
00096 /* 3D Paint */
00097 
00098 static void imapaint_project(Object *ob, float *model, float *proj, float *co, float *pco)
00099 {
00100         VECCOPY(pco, co);
00101         pco[3]= 1.0f;
00102 
00103         mul_m4_v3(ob->obmat, pco);
00104         mul_m4_v3((float(*)[4])model, pco);
00105         mul_m4_v4((float(*)[4])proj, pco);
00106 }
00107 
00108 static void imapaint_tri_weights(Object *ob, float *v1, float *v2, float *v3, float *co, float *w)
00109 {
00110         float pv1[4], pv2[4], pv3[4], h[3], divw;
00111         float model[16], proj[16], wmat[3][3], invwmat[3][3];
00112         GLint view[4];
00113 
00114         /* compute barycentric coordinates */
00115 
00116         /* get the needed opengl matrices */
00117         glGetIntegerv(GL_VIEWPORT, view);
00118         glGetFloatv(GL_MODELVIEW_MATRIX, model);
00119         glGetFloatv(GL_PROJECTION_MATRIX, proj);
00120         view[0] = view[1] = 0;
00121 
00122         /* project the verts */
00123         imapaint_project(ob, model, proj, v1, pv1);
00124         imapaint_project(ob, model, proj, v2, pv2);
00125         imapaint_project(ob, model, proj, v3, pv3);
00126 
00127         /* do inverse view mapping, see gluProject man page */
00128         h[0]= (co[0] - view[0])*2.0f/view[2] - 1;
00129         h[1]= (co[1] - view[1])*2.0f/view[3] - 1;
00130         h[2]= 1.0f;
00131 
00132         /* solve for(w1,w2,w3)/perspdiv in:
00133            h*perspdiv = Project*Model*(w1*v1 + w2*v2 + w3*v3) */
00134 
00135         wmat[0][0]= pv1[0];  wmat[1][0]= pv2[0];  wmat[2][0]= pv3[0];
00136         wmat[0][1]= pv1[1];  wmat[1][1]= pv2[1];  wmat[2][1]= pv3[1];
00137         wmat[0][2]= pv1[3];  wmat[1][2]= pv2[3];  wmat[2][2]= pv3[3];
00138 
00139         invert_m3_m3(invwmat, wmat);
00140         mul_m3_v3(invwmat, h);
00141 
00142         VECCOPY(w, h);
00143 
00144         /* w is still divided by perspdiv, make it sum to one */
00145         divw= w[0] + w[1] + w[2];
00146         if(divw != 0.0f)
00147                 mul_v3_fl(w, 1.0f/divw);
00148 }
00149 
00150 /* compute uv coordinates of mouse in face */
00151 void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, const int xy[2], float uv[2])
00152 {
00153         DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
00154         const int *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
00155         MTFace *tface = dm->getFaceDataArray(dm, CD_MTFACE), *tf;
00156         int numfaces = dm->getNumFaces(dm), a, findex;
00157         float p[2], w[3], absw, minabsw;
00158         MFace mf;
00159         MVert mv[4];
00160 
00161         minabsw = 1e10;
00162         uv[0] = uv[1] = 0.0;
00163 
00164         /* test all faces in the derivedmesh with the original index of the picked face */
00165         for(a = 0; a < numfaces; a++) {
00166                 findex= index ? index[a]: a;
00167 
00168                 if(findex == faceindex) {
00169                         dm->getFace(dm, a, &mf);
00170 
00171                         dm->getVert(dm, mf.v1, &mv[0]);
00172                         dm->getVert(dm, mf.v2, &mv[1]);
00173                         dm->getVert(dm, mf.v3, &mv[2]);
00174                         if(mf.v4)
00175                                 dm->getVert(dm, mf.v4, &mv[3]);
00176 
00177                         tf= &tface[a];
00178 
00179                         p[0]= xy[0];
00180                         p[1]= xy[1];
00181 
00182                         if(mf.v4) {
00183                                 /* the triangle with the largest absolute values is the one
00184                                    with the most negative weights */
00185                                 imapaint_tri_weights(ob, mv[0].co, mv[1].co, mv[3].co, p, w);
00186                                 absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
00187                                 if(absw < minabsw) {
00188                                         uv[0]= tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[3][0]*w[2];
00189                                         uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[3][1]*w[2];
00190                                         minabsw = absw;
00191                                 }
00192 
00193                                 imapaint_tri_weights(ob, mv[1].co, mv[2].co, mv[3].co, p, w);
00194                                 absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
00195                                 if(absw < minabsw) {
00196                                         uv[0]= tf->uv[1][0]*w[0] + tf->uv[2][0]*w[1] + tf->uv[3][0]*w[2];
00197                                         uv[1]= tf->uv[1][1]*w[0] + tf->uv[2][1]*w[1] + tf->uv[3][1]*w[2];
00198                                         minabsw = absw;
00199                                 }
00200                         }
00201                         else {
00202                                 imapaint_tri_weights(ob, mv[0].co, mv[1].co, mv[2].co, p, w);
00203                                 absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
00204                                 if(absw < minabsw) {
00205                                         uv[0]= tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[2][0]*w[2];
00206                                         uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[2][1]*w[2];
00207                                         minabsw = absw;
00208                                 }
00209                         }
00210                 }
00211         }
00212 
00213         dm->release(dm);
00214 }
00215 
00217 int imapaint_pick_face(ViewContext *vc, Mesh *me, const int mval[2], unsigned int *index)
00218 {
00219         if(!me || me->totface==0)
00220                 return 0;
00221 
00222         /* sample only on the exact position */
00223         *index = view3d_sample_backbuf(vc, mval[0], mval[1]);
00224 
00225         if((*index)<=0 || (*index)>(unsigned int)me->totface)
00226                 return 0;
00227 
00228         (*index)--;
00229         
00230         return 1;
00231 }
00232 
00233 /* used for both 3d view and image window */
00234 void paint_sample_color(Scene *scene, ARegion *ar, int x, int y)        /* frontbuf */
00235 {
00236         Brush *br = paint_brush(paint_get_active(scene));
00237         unsigned int col;
00238         char *cp;
00239 
00240         CLAMP(x, 0, ar->winx);
00241         CLAMP(y, 0, ar->winy);
00242         
00243         glReadBuffer(GL_FRONT);
00244         glReadPixels(x+ar->winrct.xmin, y+ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
00245         glReadBuffer(GL_BACK);
00246 
00247         cp = (char *)&col;
00248         
00249         if(br) {
00250                 br->rgb[0]= cp[0]/255.0f;
00251                 br->rgb[1]= cp[1]/255.0f;
00252                 br->rgb[2]= cp[2]/255.0f;
00253         }
00254 }
00255 
00256 static int brush_curve_preset_exec(bContext *C, wmOperator *op)
00257 {
00258         Brush *br = paint_brush(paint_get_active(CTX_data_scene(C)));
00259         brush_curve_preset(br, RNA_enum_get(op->ptr, "shape"));
00260 
00261         return OPERATOR_FINISHED;
00262 }
00263 
00264 static int brush_curve_preset_poll(bContext *C)
00265 {
00266         Brush *br = paint_brush(paint_get_active(CTX_data_scene(C)));
00267 
00268         return br && br->curve;
00269 }
00270 
00271 void BRUSH_OT_curve_preset(wmOperatorType *ot)
00272 {
00273         static EnumPropertyItem prop_shape_items[] = {
00274                 {CURVE_PRESET_SHARP, "SHARP", 0, "Sharp", ""},
00275                 {CURVE_PRESET_SMOOTH, "SMOOTH", 0, "Smooth", ""},
00276                 {CURVE_PRESET_MAX, "MAX", 0, "Max", ""},
00277                 {CURVE_PRESET_LINE, "LINE", 0, "Line", ""},
00278                 {CURVE_PRESET_ROUND, "ROUND", 0, "Round", ""},
00279                 {CURVE_PRESET_ROOT, "ROOT", 0, "Root", ""},
00280                 {0, NULL, 0, NULL, NULL}};
00281 
00282         ot->name= "Preset";
00283         ot->description= "Set brush shape";
00284         ot->idname= "BRUSH_OT_curve_preset";
00285 
00286         ot->exec= brush_curve_preset_exec;
00287         ot->poll= brush_curve_preset_poll;
00288 
00289         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00290 
00291         RNA_def_enum(ot->srna, "shape", prop_shape_items, CURVE_PRESET_SMOOTH, "Mode", "");
00292 }
00293 
00294 
00295 /* face-select ops */
00296 static int paint_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
00297 {
00298         paintface_select_linked(C, CTX_data_active_object(C), NULL, 2);
00299         ED_region_tag_redraw(CTX_wm_region(C));
00300         return OPERATOR_FINISHED;
00301 }
00302 
00303 void PAINT_OT_face_select_linked(wmOperatorType *ot)
00304 {
00305         ot->name= "Select Linked";
00306         ot->description= "Select linked faces";
00307         ot->idname= "PAINT_OT_face_select_linked";
00308 
00309         ot->exec= paint_select_linked_exec;
00310         ot->poll= facemask_paint_poll;
00311 
00312         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00313 }
00314 
00315 static int paint_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
00316 {
00317         int mode= RNA_boolean_get(op->ptr, "extend") ? 1:0;
00318         paintface_select_linked(C, CTX_data_active_object(C), event->mval, mode);
00319         ED_region_tag_redraw(CTX_wm_region(C));
00320         return OPERATOR_FINISHED;
00321 }
00322 
00323 void PAINT_OT_face_select_linked_pick(wmOperatorType *ot)
00324 {
00325         ot->name= "Select Linked Pick";
00326         ot->description= "Select linked faces";
00327         ot->idname= "PAINT_OT_face_select_linked_pick";
00328 
00329         ot->invoke= paint_select_linked_pick_invoke;
00330         ot->poll= facemask_paint_poll;
00331 
00332         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00333 
00334         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection");
00335 }
00336 
00337 
00338 static int face_select_all_exec(bContext *C, wmOperator *op)
00339 {
00340         Object *ob= CTX_data_active_object(C);
00341         paintface_deselect_all_visible(ob, RNA_enum_get(op->ptr, "action"), TRUE);
00342         ED_region_tag_redraw(CTX_wm_region(C));
00343         return OPERATOR_FINISHED;
00344 }
00345 
00346 
00347 void PAINT_OT_face_select_all(wmOperatorType *ot)
00348 {
00349         ot->name= "Face Selection";
00350         ot->description= "Change selection for all faces";
00351         ot->idname= "PAINT_OT_face_select_all";
00352 
00353         ot->exec= face_select_all_exec;
00354         ot->poll= facemask_paint_poll;
00355 
00356         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00357 
00358         WM_operator_properties_select_all(ot);
00359 }
00360 
00361 static int face_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
00362 {
00363         Object *ob= CTX_data_active_object(C);
00364         paintface_deselect_all_visible(ob, SEL_INVERT, TRUE);
00365         ED_region_tag_redraw(CTX_wm_region(C));
00366         return OPERATOR_FINISHED;
00367 }
00368 
00369 
00370 void PAINT_OT_face_select_inverse(wmOperatorType *ot)
00371 {
00372         ot->name= "Face Select Invert";
00373         ot->description= "Invert selection of faces";
00374         ot->idname= "PAINT_OT_face_select_inverse";
00375 
00376         ot->exec= face_select_inverse_exec;
00377         ot->poll= facemask_paint_poll;
00378 
00379         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00380 }
00381 
00382 static int face_select_hide_exec(bContext *C, wmOperator *op)
00383 {
00384         const int unselected= RNA_boolean_get(op->ptr, "unselected");
00385         Object *ob= CTX_data_active_object(C);
00386         paintface_hide(ob, unselected);
00387         ED_region_tag_redraw(CTX_wm_region(C));
00388         return OPERATOR_FINISHED;
00389 }
00390 
00391 void PAINT_OT_face_select_hide(wmOperatorType *ot)
00392 {
00393         ot->name= "Face Select Hide";
00394         ot->description= "Hide selected faces";
00395         ot->idname= "PAINT_OT_face_select_hide";
00396 
00397         ot->exec= face_select_hide_exec;
00398         ot->poll= facemask_paint_poll;
00399 
00400         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00401 
00402         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects.");
00403 }
00404 
00405 static int face_select_reveal_exec(bContext *C, wmOperator *UNUSED(op))
00406 {
00407         Object *ob= CTX_data_active_object(C);
00408         paintface_reveal(ob);
00409         ED_region_tag_redraw(CTX_wm_region(C));
00410         return OPERATOR_FINISHED;
00411 }
00412 
00413 void PAINT_OT_face_select_reveal(wmOperatorType *ot)
00414 {
00415         ot->name= "Face Select Reveal";
00416         ot->description= "Reveal hidden faces";
00417         ot->idname= "PAINT_OT_face_select_reveal";
00418 
00419         ot->exec= face_select_reveal_exec;
00420         ot->poll= facemask_paint_poll;
00421 
00422         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00423 
00424         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects.");
00425 }