diff options
Diffstat (limited to 'source/blender/editors/space_view3d/view3d_project.c')
-rw-r--r-- | source/blender/editors/space_view3d/view3d_project.c | 168 |
1 files changed, 93 insertions, 75 deletions
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index 34b983f83df..7d728234c92 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -43,6 +43,7 @@ #include "ED_view3d.h" /* own include */ #define BL_NEAR_CLIP 0.001 +#define BL_ZERO_CLIP 0.001 /* Non Clipping Projection Functions * ********************************* */ @@ -72,7 +73,7 @@ void ED_view3d_project_float_v2_m4(const ARegion *ar, const float co[3], float r /** * \note use #ED_view3d_ob_project_mat_get to get projecting mat */ -void ED_view3d_project_float_v3_m4(ARegion *ar, const float vec[3], float r_co[3], float mat[4][4]) +void ED_view3d_project_float_v3_m4(const ARegion *ar, const float vec[3], float r_co[3], float mat[4][4]) { float vec4[4]; @@ -96,7 +97,7 @@ void ED_view3d_project_float_v3_m4(ARegion *ar, const float vec[3], float r_co[3 /* Clipping Projection Functions * ***************************** */ -eV3DProjStatus ED_view3d_project_base(struct ARegion *ar, struct Base *base) +eV3DProjStatus ED_view3d_project_base(const struct ARegion *ar, struct Base *base) { eV3DProjStatus ret = ED_view3d_project_short_global(ar, base->object->obmat[3], &base->sx, V3D_PROJ_TEST_CLIP_DEFAULT); @@ -109,14 +110,14 @@ eV3DProjStatus ED_view3d_project_base(struct ARegion *ar, struct Base *base) } /* perspmat is typically... - * - 'rv3d->perspmat', is_local == FALSE - * - 'rv3d->perspmatob', is_local == TRUE + * - 'rv3d->perspmat', is_local == false + * - 'rv3d->persmatob', is_local == true */ -static eV3DProjStatus ed_view3d_project__internal(ARegion *ar, - float perspmat[4][4], const int is_local, /* normally hidden */ +static eV3DProjStatus ed_view3d_project__internal(const ARegion *ar, + float perspmat[4][4], const bool is_local, /* normally hidden */ const float co[3], float r_co[2], const eV3DProjTest flag) { - float fx, fy, vec4[4]; + float vec4[4]; /* check for bad flags */ BLI_assert((flag & V3D_PROJ_TEST_ALL) == flag); @@ -134,30 +135,43 @@ static eV3DProjStatus ed_view3d_project__internal(ARegion *ar, vec4[3] = 1.0; mul_m4_v4(perspmat, vec4); - if (vec4[3] > (float)BL_NEAR_CLIP) { - fx = ((float)ar->winx / 2.0f) * (1.0f + vec4[0] / vec4[3]); - if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fx > 0 && fx < ar->winx)) { - fy = ((float)ar->winy / 2.0f) * (1.0f + vec4[1] / vec4[3]); - if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fy > 0.0f && fy < (float)ar->winy)) { - r_co[0] = (short)floor(fx); - r_co[1] = (short)floor(fy); + + + if (((flag & V3D_PROJ_TEST_CLIP_ZERO) == 0) || (fabsf(vec4[3]) > (float)BL_ZERO_CLIP)) { + if (((flag & V3D_PROJ_TEST_CLIP_NEAR) == 0) || (vec4[3] > (float)BL_NEAR_CLIP)) { + const float scalar = (vec4[3] != 0.0f) ? (1.0f / vec4[3]): 0.0f; + const float fx = ((float)ar->winx / 2.0f) * (1.0f + (vec4[0] * scalar)); + if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fx > 0.0f && fx < (float)ar->winx)) { + const float fy = ((float)ar->winy / 2.0f) * (1.0f + (vec4[1] * scalar)); + if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fy > 0.0f && fy < (float)ar->winy)) { + r_co[0] = floorf(fx); + r_co[1] = floorf(fy); + + /* check if the point is behind the view, we need to flip in this case */ + if (UNLIKELY((flag & V3D_PROJ_TEST_CLIP_NEAR) == 0) && (vec4[3] < 0.0f)) { + negate_v2(r_co); + } + } + else { + return V3D_PROJ_RET_CLIP_WIN; + } } else { return V3D_PROJ_RET_CLIP_WIN; } } else { - return V3D_PROJ_RET_CLIP_WIN; + return V3D_PROJ_RET_CLIP_NEAR; } } else { - return V3D_PROJ_RET_CLIP_NEAR; + return V3D_PROJ_RET_CLIP_ZERO; } return V3D_PROJ_RET_OK; } -eV3DProjStatus ED_view3d_project_short_ex(ARegion *ar, float perspmat[4][4], const int is_local, +eV3DProjStatus ED_view3d_project_short_ex(const ARegion *ar, float perspmat[4][4], const bool is_local, const float co[3], short r_co[2], const eV3DProjTest flag) { float tvec[2]; @@ -166,8 +180,8 @@ eV3DProjStatus ED_view3d_project_short_ex(ARegion *ar, float perspmat[4][4], con if ((tvec[0] > -32700.0f && tvec[0] < 32700.0f) && (tvec[1] > -32700.0f && tvec[1] < 32700.0f)) { - r_co[0] = (short)floor(tvec[0]); - r_co[1] = (short)floor(tvec[1]); + r_co[0] = (short)floorf(tvec[0]); + r_co[1] = (short)floorf(tvec[1]); } else { ret = V3D_PROJ_RET_OVERFLOW; @@ -176,7 +190,7 @@ eV3DProjStatus ED_view3d_project_short_ex(ARegion *ar, float perspmat[4][4], con return ret; } -eV3DProjStatus ED_view3d_project_int_ex(ARegion *ar, float perspmat[4][4], const int is_local, +eV3DProjStatus ED_view3d_project_int_ex(const ARegion *ar, float perspmat[4][4], const bool is_local, const float co[3], int r_co[2], const eV3DProjTest flag) { float tvec[2]; @@ -185,8 +199,8 @@ eV3DProjStatus ED_view3d_project_int_ex(ARegion *ar, float perspmat[4][4], const if ((tvec[0] > -2140000000.0f && tvec[0] < 2140000000.0f) && (tvec[1] > -2140000000.0f && tvec[1] < 2140000000.0f)) { - r_co[0] = (int)floor(tvec[0]); - r_co[1] = (int)floor(tvec[1]); + r_co[0] = (int)floorf(tvec[0]); + r_co[1] = (int)floorf(tvec[1]); } else { ret = V3D_PROJ_RET_OVERFLOW; @@ -195,7 +209,7 @@ eV3DProjStatus ED_view3d_project_int_ex(ARegion *ar, float perspmat[4][4], const return ret; } -eV3DProjStatus ED_view3d_project_float_ex(ARegion *ar, float perspmat[4][4], const int is_local, +eV3DProjStatus ED_view3d_project_float_ex(const ARegion *ar, float perspmat[4][4], const bool is_local, const float co[3], float r_co[2], const eV3DProjTest flag) { float tvec[2]; @@ -214,42 +228,42 @@ eV3DProjStatus ED_view3d_project_float_ex(ARegion *ar, float perspmat[4][4], con } /* --- short --- */ -eV3DProjStatus ED_view3d_project_short_global(ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag) +eV3DProjStatus ED_view3d_project_short_global(const ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag) { RegionView3D *rv3d = ar->regiondata; - return ED_view3d_project_short_ex(ar, rv3d->persmat, FALSE, co, r_co, flag); + return ED_view3d_project_short_ex(ar, rv3d->persmat, false, co, r_co, flag); } /* object space, use ED_view3d_init_mats_rv3d before calling */ -eV3DProjStatus ED_view3d_project_short_object(ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag) +eV3DProjStatus ED_view3d_project_short_object(const ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag) { RegionView3D *rv3d = ar->regiondata; - return ED_view3d_project_short_ex(ar, rv3d->persmatob, TRUE, co, r_co, flag); + return ED_view3d_project_short_ex(ar, rv3d->persmatob, true, co, r_co, flag); } /* --- int --- */ -eV3DProjStatus ED_view3d_project_int_global(ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag) +eV3DProjStatus ED_view3d_project_int_global(const ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag) { RegionView3D *rv3d = ar->regiondata; - return ED_view3d_project_int_ex(ar, rv3d->persmat, FALSE, co, r_co, flag); + return ED_view3d_project_int_ex(ar, rv3d->persmat, false, co, r_co, flag); } /* object space, use ED_view3d_init_mats_rv3d before calling */ -eV3DProjStatus ED_view3d_project_int_object(ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag) +eV3DProjStatus ED_view3d_project_int_object(const ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag) { RegionView3D *rv3d = ar->regiondata; - return ED_view3d_project_int_ex(ar, rv3d->persmatob, TRUE, co, r_co, flag); + return ED_view3d_project_int_ex(ar, rv3d->persmatob, true, co, r_co, flag); } /* --- float --- */ -eV3DProjStatus ED_view3d_project_float_global(ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag) +eV3DProjStatus ED_view3d_project_float_global(const ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag) { RegionView3D *rv3d = ar->regiondata; - return ED_view3d_project_float_ex(ar, rv3d->persmat, FALSE, co, r_co, flag); + return ED_view3d_project_float_ex(ar, rv3d->persmat, false, co, r_co, flag); } /* object space, use ED_view3d_init_mats_rv3d before calling */ -eV3DProjStatus ED_view3d_project_float_object(ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag) +eV3DProjStatus ED_view3d_project_float_object(const ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag) { RegionView3D *rv3d = ar->regiondata; - return ED_view3d_project_float_ex(ar, rv3d->persmatob, TRUE, co, r_co, flag); + return ED_view3d_project_float_ex(ar, rv3d->persmatob, true, co, r_co, flag); } @@ -257,28 +271,30 @@ eV3DProjStatus ED_view3d_project_float_object(ARegion *ar, const float co[3], fl /* More Generic Window/Ray/Vector projection functions * *************************************************** */ -/* odd function, need to document better */ -int initgrabz(RegionView3D *rv3d, float x, float y, float z) +/** + * Caculate a depth value from \a co, use with #ED_view3d_win_to_delta + */ +float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_flip) { - int flip = FALSE; - if (rv3d == NULL) return flip; - rv3d->zfac = rv3d->persmat[0][3] * x + rv3d->persmat[1][3] * y + rv3d->persmat[2][3] * z + rv3d->persmat[3][3]; - if (rv3d->zfac < 0.0f) - flip = TRUE; + float zfac = mul_project_m4_v3_zfac((float (*)[4])rv3d->persmat, co); + + if (r_flip) { + *r_flip = (zfac < 0.0f); + } + /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that - * (accounting for near zero values) - */ - if (rv3d->zfac < 1.e-6f && rv3d->zfac > -1.e-6f) rv3d->zfac = 1.0f; + * (accounting for near zero values) */ + if (zfac < 1.e-6f && zfac > -1.e-6f) { + zfac = 1.0f; + } /* Negative zfac means x, y, z was behind the camera (in perspective). - * This gives flipped directions, so revert back to ok default case. - */ - /* NOTE: I've changed this to flip zfac to be positive again for now so that GPencil draws ok - * Aligorith, 2009Aug31 */ - //if (rv3d->zfac < 0.0f) rv3d->zfac = 1.0f; - if (rv3d->zfac < 0.0f) rv3d->zfac = -rv3d->zfac; - - return flip; + * This gives flipped directions, so revert back to ok default case. */ + if (zfac < 0.0f) { + zfac = -zfac; + } + + return zfac; } /** @@ -292,7 +308,7 @@ int initgrabz(RegionView3D *rv3d, float x, float y, float z) * \param ray_start The world-space starting point of the segment. * \param ray_normal The normalized world-space direction of towards mval. */ -void ED_view3d_win_to_ray(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3]) +void ED_view3d_win_to_ray(const ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3]) { float ray_end[3]; @@ -308,7 +324,7 @@ void ED_view3d_win_to_ray(ARegion *ar, View3D *v3d, const float mval[2], float r * \param coord The world-space location. * \param vec The resulting normalized vector. */ -void ED_view3d_global_to_vector(RegionView3D *rv3d, const float coord[3], float vec[3]) +void ED_view3d_global_to_vector(const RegionView3D *rv3d, const float coord[3], float vec[3]) { if (rv3d->is_persp) { float p1[4], p2[4]; @@ -317,11 +333,11 @@ void ED_view3d_global_to_vector(RegionView3D *rv3d, const float coord[3], float p1[3] = 1.0f; copy_v3_v3(p2, p1); p2[3] = 1.0f; - mul_m4_v4(rv3d->viewmat, p2); + mul_m4_v4((float (*)[4])rv3d->viewmat, p2); mul_v3_fl(p2, 2.0f); - mul_m4_v4(rv3d->viewinv, p2); + mul_m4_v4((float (*)[4])rv3d->viewinv, p2); sub_v3_v3v3(vec, p1, p2); } @@ -338,7 +354,7 @@ void ED_view3d_global_to_vector(RegionView3D *rv3d, const float coord[3], float * \param mval The area relative location (such as event->mval converted to floats). * \param out The resulting world-space location. */ -void ED_view3d_win_to_3d(ARegion *ar, const float depth_pt[3], const float mval[2], float out[3]) +void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float mval[2], float out[3]) { RegionView3D *rv3d = ar->regiondata; @@ -351,7 +367,7 @@ void ED_view3d_win_to_3d(ARegion *ar, const float depth_pt[3], const float mval[ ED_view3d_win_to_vector(ar, mval, mousevec); add_v3_v3v3(line_end, line_sta, mousevec); - if (isect_line_plane_v3(out, line_sta, line_end, depth_pt, rv3d->viewinv[2], TRUE) == 0) { + if (isect_line_plane_v3(out, line_sta, line_end, depth_pt, rv3d->viewinv[2], true) == 0) { /* highly unlikely to ever happen, mouse vec paralelle with view plane */ zero_v3(out); } @@ -370,19 +386,19 @@ void ED_view3d_win_to_3d(ARegion *ar, const float depth_pt[3], const float mval[ /** * Calculate a 3d difference vector from 2d window offset. - * note that initgrabz() must be called first to determine + * note that ED_view3d_calc_zfac() must be called first to determine * the depth used to calculate the delta. * \param ar The region (used for the window width and height). * \param mval The area relative 2d difference (such as event->mval[0] - other_x). * \param out The resulting world-space delta. */ -void ED_view3d_win_to_delta(ARegion *ar, const float mval[2], float out[3]) +void ED_view3d_win_to_delta(const ARegion *ar, const float mval[2], float out[3], const float zfac) { RegionView3D *rv3d = ar->regiondata; float dx, dy; - dx = 2.0f * mval[0] * rv3d->zfac / ar->winx; - dy = 2.0f * mval[1] * rv3d->zfac / ar->winy; + dx = 2.0f * mval[0] * zfac / ar->winx; + dy = 2.0f * mval[1] * zfac / ar->winy; out[0] = (rv3d->persinv[0][0] * dx + rv3d->persinv[1][0] * dy); out[1] = (rv3d->persinv[0][1] * dx + rv3d->persinv[1][1] * dy); @@ -394,7 +410,7 @@ void ED_view3d_win_to_delta(ARegion *ar, const float mval[2], float out[3]) * This direction vector starts and the view in the direction of the 2d window coordinates. * In orthographic view all window coordinates yield the same vector. * - * \note doesn't rely on initgrabz + * \note doesn't rely on ED_view3d_calc_zfac * for perspective view, get the vector direction to * the mouse cursor as a normalized vector. * @@ -402,7 +418,7 @@ void ED_view3d_win_to_delta(ARegion *ar, const float mval[2], float out[3]) * \param mval The area relative 2d location (such as event->mval converted to floats). * \param out The resulting normalized world-space direction vector. */ -void ED_view3d_win_to_vector(ARegion *ar, const float mval[2], float out[3]) +void ED_view3d_win_to_vector(const ARegion *ar, const float mval[2], float out[3]) { RegionView3D *rv3d = ar->regiondata; @@ -419,7 +435,8 @@ void ED_view3d_win_to_vector(ARegion *ar, const float mval[2], float out[3]) normalize_v3(out); } -void ED_view3d_win_to_segment(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3]) +void ED_view3d_win_to_segment(const ARegion *ar, View3D *v3d, const float mval[2], + float ray_start[3], float ray_end[3]) { RegionView3D *rv3d = ar->regiondata; @@ -456,9 +473,10 @@ void ED_view3d_win_to_segment(ARegion *ar, View3D *v3d, const float mval[2], flo * \param mval The area relative 2d location (such as event->mval, converted into float[2]). * \param ray_start The world-space starting point of the segment. * \param ray_end The world-space end point of the segment. - * \return success, FALSE if the segment is totally clipped. + * \return success, false if the segment is totally clipped. */ -int ED_view3d_win_to_segment_clip(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3]) +bool ED_view3d_win_to_segment_clip(const ARegion *ar, View3D *v3d, const float mval[2], + float ray_start[3], float ray_end[3]) { RegionView3D *rv3d = ar->regiondata; ED_view3d_win_to_segment(ar, v3d, mval, ray_start, ray_end); @@ -466,14 +484,14 @@ int ED_view3d_win_to_segment_clip(ARegion *ar, View3D *v3d, const float mval[2], /* clipping */ if (rv3d->rflag & RV3D_CLIPPING) { /* if the ray is totally clipped, - * restore the original values but return FALSE + * restore the original values but return false * caller can choose what to do */ float tray_start[3] = {UNPACK3(ray_start)}; float tray_end[3] = {UNPACK3(ray_end)}; int a; for (a = 0; a < 4; a++) { - if (clip_line_plane(tray_start, tray_end, rv3d->clip[a]) == FALSE) { - return FALSE; + if (clip_line_plane(tray_start, tray_end, rv3d->clip[a]) == false) { + return false; } } @@ -482,19 +500,19 @@ int ED_view3d_win_to_segment_clip(ARegion *ar, View3D *v3d, const float mval[2], copy_v3_v3(ray_end, tray_end); } - return TRUE; + return true; } /* Utility functions for projection * ******************************** */ -void ED_view3d_ob_project_mat_get(RegionView3D *rv3d, Object *ob, float pmat[4][4]) +void ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, Object *ob, float pmat[4][4]) { float vmat[4][4]; - mult_m4_m4m4(vmat, rv3d->viewmat, ob->obmat); - mult_m4_m4m4(pmat, rv3d->winmat, vmat); + mult_m4_m4m4(vmat, (float (*)[4])rv3d->viewmat, ob->obmat); + mult_m4_m4m4(pmat, (float (*)[4])rv3d->winmat, vmat); } /** |