fix for harmless glitch rotating the camera in camera mode, having the center point so close to the viewpoint caused the helper line to erratically move about because of float precision.

This commit is contained in:
Campbell Barton 2013-02-28 11:29:27 +00:00
parent a368334f74
commit 4f4e45540d
4 changed files with 46 additions and 23 deletions

@ -105,9 +105,10 @@ void ED_view3d_depth_tag_update(struct RegionView3D *rv3d);
typedef enum {
V3D_PROJ_RET_OK = 0,
V3D_PROJ_RET_CLIP_NEAR = 1, /* can't avoid this when in perspective mode, (can't avoid) */
V3D_PROJ_RET_CLIP_BB = 2, /* bounding box clip - RV3D_CLIPPING */
V3D_PROJ_RET_CLIP_WIN = 3, /* outside window bounds */
V3D_PROJ_RET_OVERFLOW = 4 /* outside range (mainly for short), (can't avoid) */
V3D_PROJ_RET_CLIP_ZERO = 2, /* so close to zero we can't apply a perspective matrix usefully */
V3D_PROJ_RET_CLIP_BB = 3, /* bounding box clip - RV3D_CLIPPING */
V3D_PROJ_RET_CLIP_WIN = 4, /* outside window bounds */
V3D_PROJ_RET_OVERFLOW = 5 /* outside range (mainly for short), (can't avoid) */
} eV3DProjStatus;
/* some clipping tests are optional */
@ -116,10 +117,13 @@ typedef enum {
V3D_PROJ_TEST_CLIP_BB = (1 << 0),
V3D_PROJ_TEST_CLIP_WIN = (1 << 1),
V3D_PROJ_TEST_CLIP_NEAR = (1 << 2),
V3D_PROJ_TEST_CLIP_ZERO = (1 << 3)
} eV3DProjTest;
#define V3D_PROJ_TEST_CLIP_DEFAULT (V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR)
#define V3D_PROJ_TEST_ALL (V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR)
#define V3D_PROJ_TEST_CLIP_DEFAULT \
(V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR)
#define V3D_PROJ_TEST_ALL \
(V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_ZERO)
/* view3d_iterators.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
* ********************************* */
@ -134,18 +135,25 @@ static eV3DProjStatus ed_view3d_project__internal(ARegion *ar,
vec4[3] = 1.0;
mul_m4_v4(perspmat, vec4);
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);
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 {
@ -153,11 +161,11 @@ static eV3DProjStatus ed_view3d_project__internal(ARegion *ar,
}
}
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;

@ -239,11 +239,11 @@ void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy)
}
}
void projectIntView(TransInfo *t, const float vec[3], int adr[2])
void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DProjTest flag)
{
if (t->spacetype == SPACE_VIEW3D) {
if (t->ar->regiontype == RGN_TYPE_WINDOW) {
if (ED_view3d_project_int_global(t->ar, vec, adr, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
if (ED_view3d_project_int_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) {
adr[0] = (int)2140000000.0f; /* this is what was done in 2.64, perhaps we can be smarter? */
adr[1] = (int)2140000000.0f;
}
@ -361,15 +361,19 @@ void projectIntView(TransInfo *t, const float vec[3], int adr[2])
UI_view2d_to_region_no_clip((View2D *)t->view, vec[0], vec[1], adr, adr + 1);
}
}
void projectIntView(TransInfo *t, const float vec[3], int adr[2])
{
projectIntViewEx(t, vec, adr, V3D_PROJ_TEST_NOP);
}
void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV3DProjTest flag)
{
switch (t->spacetype) {
case SPACE_VIEW3D:
{
if (t->ar->regiontype == RGN_TYPE_WINDOW) {
/* allow points behind the view [#33643] */
if (ED_view3d_project_float_global(t->ar, vec, adr, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
if (ED_view3d_project_float_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) {
/* XXX, 2.64 and prior did this, weak! */
adr[0] = t->ar->winx / 2.0f;
adr[1] = t->ar->winy / 2.0f;
@ -393,6 +397,10 @@ void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
zero_v2(adr);
}
void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
{
projectFloatViewEx(t, vec, adr, V3D_PROJ_TEST_NOP);
}
void applyAspectRatio(TransInfo *t, float vec[2])
{
@ -1543,7 +1551,7 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
if (ob) mul_m4_v3(ob->obmat, vecrot);
}
projectFloatView(t, vecrot, cent); // no overflow in extreme cases
projectFloatViewEx(t, vecrot, cent, V3D_PROJ_TEST_CLIP_ZERO);
glPushMatrix();

@ -35,6 +35,7 @@
#include "ED_transform.h"
#include "ED_numinput.h"
#include "ED_view3d.h"
#include "DNA_listBase.h"
@ -481,7 +482,9 @@ int transformEnd(struct bContext *C, TransInfo *t);
void setTransformViewMatrices(TransInfo *t);
void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy);
void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DProjTest flag);
void projectIntView(TransInfo *t, const float vec[3], int adr[2]);
void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV3DProjTest flag);
void projectFloatView(TransInfo *t, const float vec[3], float adr[2]);
void applyAspectRatio(TransInfo *t, float *vec);