Blender V2.61 - r43446

paint_utils.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00032 #include <math.h>
00033 #include <stdlib.h>
00034 
00035 #include "DNA_mesh_types.h"
00036 #include "DNA_meshdata_types.h"
00037 #include "DNA_object_types.h"
00038 
00039 #include "DNA_scene_types.h"
00040 #include "DNA_brush_types.h"
00041 
00042 #include "BLI_math.h"
00043 #include "BLI_utildefines.h"
00044 
00045 #include "BKE_brush.h"
00046 #include "BKE_context.h"
00047 #include "BKE_DerivedMesh.h"
00048 #include "BKE_paint.h"
00049 
00050 #include "RNA_access.h"
00051 #include "RNA_define.h"
00052 
00053 #include "BIF_gl.h"
00054 /* TODO: remove once projectf goes away */
00055 #include "BIF_glutil.h"
00056 
00057 #include "RE_shader_ext.h"
00058 
00059 #include "ED_view3d.h"
00060 #include "ED_screen.h"
00061 
00062 #include "BLO_sys_types.h"
00063 #include "ED_mesh.h" /* for face mask functions */
00064 
00065 #include "WM_api.h"
00066 #include "WM_types.h"
00067 
00068 #include "paint_intern.h"
00069 
00070 /* Convert the object-space axis-aligned bounding box (expressed as
00071    its minimum and maximum corners) into a screen-space rectangle,
00072    returns zero if the result is empty */
00073 int paint_convert_bb_to_rect(rcti *rect,
00074                              const float bb_min[3],
00075                              const float bb_max[3],
00076                              const ARegion *ar,
00077                              RegionView3D *rv3d,
00078                              Object *ob)
00079 {
00080     float projection_mat[4][4];
00081     int i, j, k;
00082 
00083     rect->xmin = rect->ymin = INT_MAX;
00084     rect->xmax = rect->ymax = INT_MIN;
00085 
00086     /* return zero if the bounding box has non-positive volume */
00087     if(bb_min[0] > bb_max[0] || bb_min[1] > bb_max[1] || bb_min[2] > bb_max[2])
00088         return 0;
00089 
00090     ED_view3d_ob_project_mat_get(rv3d, ob, projection_mat);
00091 
00092     for(i = 0; i < 2; ++i) {
00093         for(j = 0; j < 2; ++j) {
00094             for(k = 0; k < 2; ++k) {
00095                 float vec[3], proj[2];
00096                 vec[0] = i ? bb_min[0] : bb_max[0];
00097                 vec[1] = j ? bb_min[1] : bb_max[1];
00098                 vec[2] = k ? bb_min[2] : bb_max[2];
00099                 /* convert corner to screen space */
00100                 ED_view3d_project_float(ar, vec, proj,
00101                                         projection_mat);
00102                 /* expand 2D rectangle */
00103                 rect->xmin = MIN2(rect->xmin, proj[0]);
00104                 rect->xmax = MAX2(rect->xmax, proj[0]);
00105                 rect->ymin = MIN2(rect->ymin, proj[1]);
00106                 rect->ymax = MAX2(rect->ymax, proj[1]);
00107             }
00108         }
00109     }
00110 
00111     /* return false if the rectangle has non-positive area */
00112     return rect->xmin < rect->xmax && rect->ymin < rect->ymax;
00113 }
00114 
00115 /* Get four planes in object-space that describe the projection of
00116    screen_rect from screen into object-space (essentially converting a
00117    2D screens-space bounding box into four 3D planes) */
00118 void paint_calc_redraw_planes(float planes[4][4],
00119                               const ARegion *ar,
00120                               RegionView3D *rv3d,
00121                               Object *ob,
00122                               const rcti *screen_rect)
00123 {
00124     BoundBox bb;
00125     bglMats mats;
00126     rcti rect;
00127 
00128     memset(&bb, 0, sizeof(BoundBox));
00129     view3d_get_transformation(ar, rv3d, ob, &mats);
00130 
00131     /* use some extra space just in case */
00132     rect = *screen_rect;
00133     rect.xmin -= 2;
00134     rect.xmax += 2;
00135     rect.ymin -= 2;
00136     rect.ymax += 2;
00137 
00138     ED_view3d_calc_clipping(&bb, planes, &mats, &rect);
00139     mul_m4_fl(planes, -1.0f);
00140 }
00141 
00142 /* convert a point in model coordinates to 2D screen coordinates */
00143 /* TODO: can be deleted once all calls are replaced with
00144    view3d_project_float() */
00145 void projectf(bglMats *mats, const float v[3], float p[2])
00146 {
00147     double ux, uy, uz;
00148 
00149     gluProject(v[0],v[1],v[2], mats->modelview, mats->projection,
00150            (GLint *)mats->viewport, &ux, &uy, &uz);
00151     p[0]= ux;
00152     p[1]= uy;
00153 }
00154 
00155 float paint_calc_object_space_radius(ViewContext *vc, const float center[3],
00156                      float pixel_radius)
00157 {
00158     Object *ob = vc->obact;
00159     float delta[3], scale, loc[3];
00160     float mval_f[2];
00161 
00162     mul_v3_m4v3(loc, ob->obmat, center);
00163 
00164     initgrabz(vc->rv3d, loc[0], loc[1], loc[2]);
00165 
00166     mval_f[0]= pixel_radius;
00167     mval_f[1]= 0.0f;
00168     ED_view3d_win_to_delta(vc->ar, mval_f, delta);
00169 
00170     scale= fabsf(mat4_to_scale(ob->obmat));
00171     scale= (scale == 0.0f)? 1.0f: scale;
00172 
00173     return len_v3(delta)/scale;
00174 }
00175 
00176 float paint_get_tex_pixel(Brush* br, float u, float v)
00177 {
00178     TexResult texres;
00179     float co[3];
00180     int hasrgb;
00181 
00182     co[0] = u;
00183     co[1] = v;
00184     co[2] = 0;
00185 
00186     memset(&texres, 0, sizeof(TexResult));
00187     hasrgb = multitex_ext(br->mtex.tex, co, NULL, NULL, 0, &texres);
00188 
00189     if (hasrgb & TEX_RGB)
00190         texres.tin = (0.35f*texres.tr + 0.45f*texres.tg + 0.2f*texres.tb)*texres.ta;
00191 
00192     return texres.tin;
00193 }
00194 
00195 /* 3D Paint */
00196 
00197 static void imapaint_project(Object *ob, float *model, float *proj, float *co, float *pco)
00198 {
00199     copy_v3_v3(pco, co);
00200     pco[3]= 1.0f;
00201 
00202     mul_m4_v3(ob->obmat, pco);
00203     mul_m4_v3((float(*)[4])model, pco);
00204     mul_m4_v4((float(*)[4])proj, pco);
00205 }
00206 
00207 static void imapaint_tri_weights(Object *ob, float *v1, float *v2, float *v3, float *co, float *w)
00208 {
00209     float pv1[4], pv2[4], pv3[4], h[3], divw;
00210     float model[16], proj[16], wmat[3][3], invwmat[3][3];
00211     GLint view[4];
00212 
00213     /* compute barycentric coordinates */
00214 
00215     /* get the needed opengl matrices */
00216     glGetIntegerv(GL_VIEWPORT, view);
00217     glGetFloatv(GL_MODELVIEW_MATRIX, model);
00218     glGetFloatv(GL_PROJECTION_MATRIX, proj);
00219     view[0] = view[1] = 0;
00220 
00221     /* project the verts */
00222     imapaint_project(ob, model, proj, v1, pv1);
00223     imapaint_project(ob, model, proj, v2, pv2);
00224     imapaint_project(ob, model, proj, v3, pv3);
00225 
00226     /* do inverse view mapping, see gluProject man page */
00227     h[0]= (co[0] - view[0])*2.0f/view[2] - 1;
00228     h[1]= (co[1] - view[1])*2.0f/view[3] - 1;
00229     h[2]= 1.0f;
00230 
00231     /* solve for(w1,w2,w3)/perspdiv in:
00232        h*perspdiv = Project*Model*(w1*v1 + w2*v2 + w3*v3) */
00233 
00234     wmat[0][0]= pv1[0];  wmat[1][0]= pv2[0];  wmat[2][0]= pv3[0];
00235     wmat[0][1]= pv1[1];  wmat[1][1]= pv2[1];  wmat[2][1]= pv3[1];
00236     wmat[0][2]= pv1[3];  wmat[1][2]= pv2[3];  wmat[2][2]= pv3[3];
00237 
00238     invert_m3_m3(invwmat, wmat);
00239     mul_m3_v3(invwmat, h);
00240 
00241     copy_v3_v3(w, h);
00242 
00243     /* w is still divided by perspdiv, make it sum to one */
00244     divw= w[0] + w[1] + w[2];
00245     if(divw != 0.0f)
00246         mul_v3_fl(w, 1.0f/divw);
00247 }
00248 
00249 /* compute uv coordinates of mouse in face */
00250 void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, const int xy[2], float uv[2])
00251 {
00252     DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
00253     const int *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
00254     MTFace *tface = dm->getFaceDataArray(dm, CD_MTFACE), *tf;
00255     int numfaces = dm->getNumFaces(dm), a, findex;
00256     float p[2], w[3], absw, minabsw;
00257     MFace mf;
00258     MVert mv[4];
00259 
00260     minabsw = 1e10;
00261     uv[0] = uv[1] = 0.0;
00262 
00263     /* test all faces in the derivedmesh with the original index of the picked face */
00264     for(a = 0; a < numfaces; a++) {
00265         findex= index ? index[a]: a;
00266 
00267         if(findex == faceindex) {
00268             dm->getFace(dm, a, &mf);
00269 
00270             dm->getVert(dm, mf.v1, &mv[0]);
00271             dm->getVert(dm, mf.v2, &mv[1]);
00272             dm->getVert(dm, mf.v3, &mv[2]);
00273             if(mf.v4)
00274                 dm->getVert(dm, mf.v4, &mv[3]);
00275 
00276             tf= &tface[a];
00277 
00278             p[0]= xy[0];
00279             p[1]= xy[1];
00280 
00281             if(mf.v4) {
00282                 /* the triangle with the largest absolute values is the one
00283                    with the most negative weights */
00284                 imapaint_tri_weights(ob, mv[0].co, mv[1].co, mv[3].co, p, w);
00285                 absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
00286                 if(absw < minabsw) {
00287                     uv[0]= tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[3][0]*w[2];
00288                     uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[3][1]*w[2];
00289                     minabsw = absw;
00290                 }
00291 
00292                 imapaint_tri_weights(ob, mv[1].co, mv[2].co, mv[3].co, p, w);
00293                 absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
00294                 if(absw < minabsw) {
00295                     uv[0]= tf->uv[1][0]*w[0] + tf->uv[2][0]*w[1] + tf->uv[3][0]*w[2];
00296                     uv[1]= tf->uv[1][1]*w[0] + tf->uv[2][1]*w[1] + tf->uv[3][1]*w[2];
00297                     minabsw = absw;
00298                 }
00299             }
00300             else {
00301                 imapaint_tri_weights(ob, mv[0].co, mv[1].co, mv[2].co, p, w);
00302                 absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
00303                 if(absw < minabsw) {
00304                     uv[0]= tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[2][0]*w[2];
00305                     uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[2][1]*w[2];
00306                     minabsw = absw;
00307                 }
00308             }
00309         }
00310     }
00311 
00312     dm->release(dm);
00313 }
00314 
00316 int imapaint_pick_face(ViewContext *vc, Mesh *me, const int mval[2], unsigned int *index)
00317 {
00318     if(!me || me->totface==0)
00319         return 0;
00320 
00321     /* sample only on the exact position */
00322     *index = view3d_sample_backbuf(vc, mval[0], mval[1]);
00323 
00324     if((*index)<=0 || (*index)>(unsigned int)me->totface)
00325         return 0;
00326 
00327     (*index)--;
00328     
00329     return 1;
00330 }
00331 
00332 /* used for both 3d view and image window */
00333 void paint_sample_color(Scene *scene, ARegion *ar, int x, int y)    /* frontbuf */
00334 {
00335     Brush *br = paint_brush(paint_get_active(scene));
00336     unsigned int col;
00337     char *cp;
00338 
00339     CLAMP(x, 0, ar->winx);
00340     CLAMP(y, 0, ar->winy);
00341     
00342     glReadBuffer(GL_FRONT);
00343     glReadPixels(x+ar->winrct.xmin, y+ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
00344     glReadBuffer(GL_BACK);
00345 
00346     cp = (char *)&col;
00347     
00348     if(br) {
00349         br->rgb[0]= cp[0]/255.0f;
00350         br->rgb[1]= cp[1]/255.0f;
00351         br->rgb[2]= cp[2]/255.0f;
00352     }
00353 }
00354 
00355 static int brush_curve_preset_exec(bContext *C, wmOperator *op)
00356 {
00357     Brush *br = paint_brush(paint_get_active(CTX_data_scene(C)));
00358     brush_curve_preset(br, RNA_enum_get(op->ptr, "shape"));
00359 
00360     return OPERATOR_FINISHED;
00361 }
00362 
00363 static int brush_curve_preset_poll(bContext *C)
00364 {
00365     Brush *br = paint_brush(paint_get_active(CTX_data_scene(C)));
00366 
00367     return br && br->curve;
00368 }
00369 
00370 void BRUSH_OT_curve_preset(wmOperatorType *ot)
00371 {
00372     static EnumPropertyItem prop_shape_items[] = {
00373         {CURVE_PRESET_SHARP, "SHARP", 0, "Sharp", ""},
00374         {CURVE_PRESET_SMOOTH, "SMOOTH", 0, "Smooth", ""},
00375         {CURVE_PRESET_MAX, "MAX", 0, "Max", ""},
00376         {CURVE_PRESET_LINE, "LINE", 0, "Line", ""},
00377         {CURVE_PRESET_ROUND, "ROUND", 0, "Round", ""},
00378         {CURVE_PRESET_ROOT, "ROOT", 0, "Root", ""},
00379         {0, NULL, 0, NULL, NULL}};
00380 
00381     ot->name= "Preset";
00382     ot->description= "Set brush shape";
00383     ot->idname= "BRUSH_OT_curve_preset";
00384 
00385     ot->exec= brush_curve_preset_exec;
00386     ot->poll= brush_curve_preset_poll;
00387 
00388     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00389 
00390     RNA_def_enum(ot->srna, "shape", prop_shape_items, CURVE_PRESET_SMOOTH, "Mode", "");
00391 }
00392 
00393 
00394 /* face-select ops */
00395 static int paint_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
00396 {
00397     paintface_select_linked(C, CTX_data_active_object(C), NULL, 2);
00398     ED_region_tag_redraw(CTX_wm_region(C));
00399     return OPERATOR_FINISHED;
00400 }
00401 
00402 void PAINT_OT_face_select_linked(wmOperatorType *ot)
00403 {
00404     ot->name= "Select Linked";
00405     ot->description= "Select linked faces";
00406     ot->idname= "PAINT_OT_face_select_linked";
00407 
00408     ot->exec= paint_select_linked_exec;
00409     ot->poll= facemask_paint_poll;
00410 
00411     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00412 }
00413 
00414 static int paint_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
00415 {
00416     int mode= RNA_boolean_get(op->ptr, "extend") ? 1:0;
00417     paintface_select_linked(C, CTX_data_active_object(C), event->mval, mode);
00418     ED_region_tag_redraw(CTX_wm_region(C));
00419     return OPERATOR_FINISHED;
00420 }
00421 
00422 void PAINT_OT_face_select_linked_pick(wmOperatorType *ot)
00423 {
00424     ot->name= "Select Linked Pick";
00425     ot->description= "Select linked faces";
00426     ot->idname= "PAINT_OT_face_select_linked_pick";
00427 
00428     ot->invoke= paint_select_linked_pick_invoke;
00429     ot->poll= facemask_paint_poll;
00430 
00431     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00432 
00433     RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection");
00434 }
00435 
00436 
00437 static int face_select_all_exec(bContext *C, wmOperator *op)
00438 {
00439     Object *ob= CTX_data_active_object(C);
00440     paintface_deselect_all_visible(ob, RNA_enum_get(op->ptr, "action"), TRUE);
00441     ED_region_tag_redraw(CTX_wm_region(C));
00442     return OPERATOR_FINISHED;
00443 }
00444 
00445 
00446 void PAINT_OT_face_select_all(wmOperatorType *ot)
00447 {
00448     ot->name= "Face Selection";
00449     ot->description= "Change selection for all faces";
00450     ot->idname= "PAINT_OT_face_select_all";
00451 
00452     ot->exec= face_select_all_exec;
00453     ot->poll= facemask_paint_poll;
00454 
00455     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00456 
00457     WM_operator_properties_select_all(ot);
00458 }
00459 
00460 
00461 static int vert_select_all_exec(bContext *C, wmOperator *op)
00462 {
00463     Object *ob= CTX_data_active_object(C);
00464     paintvert_deselect_all_visible(ob, RNA_enum_get(op->ptr, "action"), TRUE);
00465     ED_region_tag_redraw(CTX_wm_region(C));
00466     return OPERATOR_FINISHED;
00467 }
00468 
00469 
00470 void PAINT_OT_vert_select_all(wmOperatorType *ot)
00471 {
00472     ot->name= "Vertex Selection";
00473     ot->description= "Change selection for all vertices";
00474     ot->idname= "PAINT_OT_vert_select_all";
00475 
00476     ot->exec= vert_select_all_exec;
00477     ot->poll= vert_paint_poll;
00478 
00479     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00480 
00481     WM_operator_properties_select_all(ot);
00482 }
00483 
00484 static int vert_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
00485 {
00486     Object *ob= CTX_data_active_object(C);
00487     paintvert_deselect_all_visible(ob, SEL_INVERT, TRUE);
00488     ED_region_tag_redraw(CTX_wm_region(C));
00489     return OPERATOR_FINISHED;
00490 }
00491 
00492 void PAINT_OT_vert_select_inverse(wmOperatorType *ot)
00493 {
00494     ot->name= "Vertex Select Invert";
00495     ot->description= "Invert selection of vertices";
00496     ot->idname= "PAINT_OT_vert_select_inverse";
00497 
00498     ot->exec= vert_select_inverse_exec;
00499     ot->poll= vert_paint_poll;
00500 
00501     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00502 }
00503 static int face_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
00504 {
00505     Object *ob= CTX_data_active_object(C);
00506     paintface_deselect_all_visible(ob, SEL_INVERT, TRUE);
00507     ED_region_tag_redraw(CTX_wm_region(C));
00508     return OPERATOR_FINISHED;
00509 }
00510 
00511 
00512 void PAINT_OT_face_select_inverse(wmOperatorType *ot)
00513 {
00514     ot->name= "Face Select Invert";
00515     ot->description= "Invert selection of faces";
00516     ot->idname= "PAINT_OT_face_select_inverse";
00517 
00518     ot->exec= face_select_inverse_exec;
00519     ot->poll= facemask_paint_poll;
00520 
00521     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00522 }
00523 
00524 static int face_select_hide_exec(bContext *C, wmOperator *op)
00525 {
00526     const int unselected= RNA_boolean_get(op->ptr, "unselected");
00527     Object *ob= CTX_data_active_object(C);
00528     paintface_hide(ob, unselected);
00529     ED_region_tag_redraw(CTX_wm_region(C));
00530     return OPERATOR_FINISHED;
00531 }
00532 
00533 void PAINT_OT_face_select_hide(wmOperatorType *ot)
00534 {
00535     ot->name= "Face Select Hide";
00536     ot->description= "Hide selected faces";
00537     ot->idname= "PAINT_OT_face_select_hide";
00538 
00539     ot->exec= face_select_hide_exec;
00540     ot->poll= facemask_paint_poll;
00541 
00542     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00543 
00544     RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects");
00545 }
00546 
00547 static int face_select_reveal_exec(bContext *C, wmOperator *UNUSED(op))
00548 {
00549     Object *ob= CTX_data_active_object(C);
00550     paintface_reveal(ob);
00551     ED_region_tag_redraw(CTX_wm_region(C));
00552     return OPERATOR_FINISHED;
00553 }
00554 
00555 void PAINT_OT_face_select_reveal(wmOperatorType *ot)
00556 {
00557     ot->name= "Face Select Reveal";
00558     ot->description= "Reveal hidden faces";
00559     ot->idname= "PAINT_OT_face_select_reveal";
00560 
00561     ot->exec= face_select_reveal_exec;
00562     ot->poll= facemask_paint_poll;
00563 
00564     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00565 
00566     RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects");
00567 }