diff options
Diffstat (limited to 'source/blender/editors/space_view3d/view3d_edit.c')
-rw-r--r-- | source/blender/editors/space_view3d/view3d_edit.c | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 16ac8cedef0..a4dc27ceac1 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -894,6 +894,271 @@ void ED_VIEW3D_OT_viewcenter(wmOperatorType *ot) ot->poll= ED_operator_areaactive; } +/* ********************* set clipping operator ****************** */ + +static int view3d_clipping_exec(bContext *C, wmOperator *op) +{ + ScrArea *sa= CTX_wm_area(C); + View3D *v3d= sa->spacedata.first; + rcti rect; + double mvmatrix[16]; + double projmatrix[16]; + double xs, ys, p[3]; + GLint viewport[4]; + short val; + + rect.xmin= RNA_int_get(op->ptr, "xmin"); + rect.ymin= RNA_int_get(op->ptr, "ymin"); + rect.xmax= RNA_int_get(op->ptr, "xmax"); + rect.ymax= RNA_int_get(op->ptr, "ymax"); + + v3d->flag |= V3D_CLIPPING; + v3d->clipbb= MEM_callocN(sizeof(BoundBox), "clipbb"); + + /* note; otherwise opengl won't work */ + view3d_operator_needs_opengl(C); + + /* Get the matrices needed for gluUnProject */ + glGetIntegerv(GL_VIEWPORT, viewport); + glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix); + glGetDoublev(GL_PROJECTION_MATRIX, projmatrix); + + /* near zero floating point values can give issues with gluUnProject + in side view on some implementations */ + if(fabs(mvmatrix[0]) < 1e-6) mvmatrix[0]= 0.0; + if(fabs(mvmatrix[5]) < 1e-6) mvmatrix[5]= 0.0; + + /* Set up viewport so that gluUnProject will give correct values */ + viewport[0] = 0; + viewport[1] = 0; + + /* four clipping planes and bounding volume */ + /* first do the bounding volume */ + for(val=0; val<4; val++) { + + xs= (val==0||val==3)?rect.xmin:rect.xmax; + ys= (val==0||val==1)?rect.ymin:rect.ymax; + + gluUnProject(xs, ys, 0.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]); + VECCOPY(v3d->clipbb->vec[val], p); + + gluUnProject(xs, ys, 1.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]); + VECCOPY(v3d->clipbb->vec[4+val], p); + } + + /* then plane equations */ + for(val=0; val<4; val++) { + + CalcNormFloat(v3d->clipbb->vec[val], v3d->clipbb->vec[val==3?0:val+1], v3d->clipbb->vec[val+4], + v3d->clip[val]); + + v3d->clip[val][3]= - v3d->clip[val][0]*v3d->clipbb->vec[val][0] + - v3d->clip[val][1]*v3d->clipbb->vec[val][1] + - v3d->clip[val][2]*v3d->clipbb->vec[val][2]; + } + return OPERATOR_FINISHED; +} + +static int view3d_clipping_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + ScrArea *sa= CTX_wm_area(C); + View3D *v3d= sa->spacedata.first; + + if(v3d->flag & V3D_CLIPPING) { + v3d->flag &= ~V3D_CLIPPING; + ED_area_tag_redraw(sa); + if(v3d->clipbb) MEM_freeN(v3d->clipbb); + v3d->clipbb= NULL; + return OPERATOR_FINISHED; + } + else { + return WM_border_select_invoke(C, op, event); + } +} + +/* toggles */ +void ED_VIEW3D_OT_clipping(wmOperatorType *ot) +{ + + /* identifiers */ + ot->name= "Border Select"; + ot->idname= "ED_VIEW3D_OT_clipping"; + + /* api callbacks */ + ot->invoke= view3d_clipping_invoke; + ot->exec= view3d_clipping_exec; + ot->modal= WM_border_select_modal; + + ot->poll= ED_operator_areaactive; + + /* rna */ + RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE); + RNA_def_property(ot->srna, "xmax", PROP_INT, PROP_NONE); + RNA_def_property(ot->srna, "ymin", PROP_INT, PROP_NONE); + RNA_def_property(ot->srna, "ymax", PROP_INT, PROP_NONE); +} + +/* ********************************************************* */ + +void set_render_border(Scene *scene, ARegion *ar, View3D *v3d) +{ + rcti rect; + short val; + + val= 0; // XXX get_border(&rect, 3); + if(val) { + rctf vb; + + calc_viewborder(scene, ar, v3d, &vb); + + scene->r.border.xmin= ((float)rect.xmin-vb.xmin)/(vb.xmax-vb.xmin); + scene->r.border.ymin= ((float)rect.ymin-vb.ymin)/(vb.ymax-vb.ymin); + scene->r.border.xmax= ((float)rect.xmax-vb.xmin)/(vb.xmax-vb.xmin); + scene->r.border.ymax= ((float)rect.ymax-vb.ymin)/(vb.ymax-vb.ymin); + + CLAMP(scene->r.border.xmin, 0.0, 1.0); + CLAMP(scene->r.border.ymin, 0.0, 1.0); + CLAMP(scene->r.border.xmax, 0.0, 1.0); + CLAMP(scene->r.border.ymax, 0.0, 1.0); + + /* drawing a border surrounding the entire camera view switches off border rendering + * or the border covers no pixels */ + if ((scene->r.border.xmin <= 0.0 && scene->r.border.xmax >= 1.0 && + scene->r.border.ymin <= 0.0 && scene->r.border.ymax >= 1.0) || + (scene->r.border.xmin == scene->r.border.xmax || + scene->r.border.ymin == scene->r.border.ymax )) + { + scene->r.mode &= ~R_BORDER; + } else { + scene->r.mode |= R_BORDER; + } + } +} + +void view3d_border_zoom(Scene *scene, ARegion *ar, View3D *v3d) +{ + + /* Zooms in on a border drawn by the user */ + rcti rect; + short val; + float dvec[3], vb[2], xscale, yscale, scale; + + + /* SMOOTHVIEW */ + float new_dist; + float new_ofs[3]; + + /* ZBuffer depth vars */ + bglMats mats; + float depth, depth_close= MAXFLOAT; + int had_depth = 0; + double cent[2], p[3]; + int xs, ys; + + /* Get the border input */ + val = 0; // XXX get_border(&rect, 3); + if(!val) return; + + /* Get Z Depths, needed for perspective, nice for ortho */ + bgl_get_mats(&mats); + draw_depth(scene, ar, v3d, NULL); + + /* force updating */ + if (v3d->depths) { + had_depth = 1; + v3d->depths->damaged = 1; + } + + view3d_update_depths(ar, v3d); + + /* Constrain rect to depth bounds */ + if (rect.xmin < 0) rect.xmin = 0; + if (rect.ymin < 0) rect.ymin = 0; + if (rect.xmax >= v3d->depths->w) rect.xmax = v3d->depths->w-1; + if (rect.ymax >= v3d->depths->h) rect.ymax = v3d->depths->h-1; + + /* Find the closest Z pixel */ + for (xs=rect.xmin; xs < rect.xmax; xs++) { + for (ys=rect.ymin; ys < rect.ymax; ys++) { + depth= v3d->depths->depths[ys*v3d->depths->w+xs]; + if(depth < v3d->depths->depth_range[1] && depth > v3d->depths->depth_range[0]) { + if (depth_close > depth) { + depth_close = depth; + } + } + } + } + + if (had_depth==0) { + MEM_freeN(v3d->depths->depths); + v3d->depths->depths = NULL; + } + v3d->depths->damaged = 1; + + cent[0] = (((double)rect.xmin)+((double)rect.xmax)) / 2; + cent[1] = (((double)rect.ymin)+((double)rect.ymax)) / 2; + + if (v3d->persp==V3D_PERSP) { + double p_corner[3]; + + /* no depths to use, we cant do anything! */ + if (depth_close==MAXFLOAT) + return; + + /* convert border to 3d coordinates */ + if (( !gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) || + ( !gluUnProject((double)rect.xmin, (double)rect.ymin, depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p_corner[0], &p_corner[1], &p_corner[2]))) + return; + + dvec[0] = p[0]-p_corner[0]; + dvec[1] = p[1]-p_corner[1]; + dvec[2] = p[2]-p_corner[2]; + + new_dist = VecLength(dvec); + if(new_dist <= v3d->near*1.5) new_dist= v3d->near*1.5; + + new_ofs[0] = -p[0]; + new_ofs[1] = -p[1]; + new_ofs[2] = -p[2]; + + } else { /* othographic */ + /* find the current window width and height */ + vb[0] = ar->winx; + vb[1] = ar->winy; + + new_dist = v3d->dist; + + /* convert the drawn rectangle into 3d space */ + if (depth_close!=MAXFLOAT && gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) { + new_ofs[0] = -p[0]; + new_ofs[1] = -p[1]; + new_ofs[2] = -p[2]; + } else { + /* We cant use the depth, fallback to the old way that dosnt set the center depth */ + new_ofs[0] = v3d->ofs[0]; + new_ofs[1] = v3d->ofs[1]; + new_ofs[2] = v3d->ofs[2]; + + initgrabz(v3d, -new_ofs[0], -new_ofs[1], -new_ofs[2]); + + window_to_3d(ar, v3d, dvec, (rect.xmin+rect.xmax-vb[0])/2, (rect.ymin+rect.ymax-vb[1])/2); + /* center the view to the center of the rectangle */ + VecSubf(new_ofs, new_ofs, dvec); + } + + /* work out the ratios, so that everything selected fits when we zoom */ + xscale = ((rect.xmax-rect.xmin)/vb[0]); + yscale = ((rect.ymax-rect.ymin)/vb[1]); + scale = (xscale >= yscale)?xscale:yscale; + + /* zoom in as required, or as far as we can go */ + new_dist = ((new_dist*scale) >= 0.001*v3d->grid)? new_dist*scale:0.001*v3d->grid; + } + + smooth_view(v3d, new_ofs, NULL, &new_dist, NULL); +} + + /* ************************* below the line! *********************** */ |